forked from enviPath/enviPy
Compare commits
19 Commits
beta_#1
...
beta_2025-
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a4c8d96c3 | |||
| 97d0527565 | |||
| b45c99f7d3 | |||
| b95ec98a2f | |||
| c79a1f2040 | |||
| 6e6b394289 | |||
| ec387cc12e | |||
| a7637d046a | |||
| fc8192fb0d | |||
| c3c1d4f5cf | |||
| 3308d47071 | |||
| 1267ca8ace | |||
| ec52b8872d | |||
| 579cd519d0 | |||
| 280ddc7205 | |||
| c9d6d8b024 | |||
| a1aebfa54d | |||
| 79b4b1586c | |||
| aec61151ce |
@ -260,6 +260,8 @@ CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
|
|||||||
CELERY_ACCEPT_CONTENT = ['json']
|
CELERY_ACCEPT_CONTENT = ['json']
|
||||||
CELERY_TASK_SERIALIZER = 'json'
|
CELERY_TASK_SERIALIZER = 'json'
|
||||||
|
|
||||||
|
MODEL_BUILDING_ENABLED = os.environ.get('MODEL_BUILDING_ENABLED', 'False') == 'True'
|
||||||
|
APPLICABILITY_DOMAIN_ENABLED = os.environ.get('APPLICABILITY_DOMAIN_ENABLED', 'False') == 'True'
|
||||||
DEFAULT_RF_MODEL_PARAMS = {
|
DEFAULT_RF_MODEL_PARAMS = {
|
||||||
'base_clf': RandomForestClassifier(
|
'base_clf': RandomForestClassifier(
|
||||||
n_estimators=100,
|
n_estimators=100,
|
||||||
@ -273,14 +275,14 @@ DEFAULT_RF_MODEL_PARAMS = {
|
|||||||
'num_chains': 10,
|
'num_chains': 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_DT_MODEL_PARAMS = {
|
DEFAULT_MODEL_PARAMS = {
|
||||||
'base_clf': DecisionTreeClassifier(
|
'base_clf': DecisionTreeClassifier(
|
||||||
criterion='entropy',
|
criterion='entropy',
|
||||||
max_depth=3,
|
max_depth=3,
|
||||||
min_samples_split=5,
|
min_samples_split=5,
|
||||||
min_samples_leaf=5,
|
# min_samples_leaf=5,
|
||||||
max_features='sqrt',
|
max_features='sqrt',
|
||||||
class_weight='balanced',
|
# class_weight='balanced',
|
||||||
random_state=42
|
random_state=42
|
||||||
),
|
),
|
||||||
'num_chains': 10,
|
'num_chains': 10,
|
||||||
@ -312,3 +314,13 @@ if SENTRY_ENABLED:
|
|||||||
# see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
|
# see https://docs.sentry.io/platforms/python/data-management/data-collected/ for more info
|
||||||
send_default_pii=True,
|
send_default_pii=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# compile into digestible flags
|
||||||
|
FLAGS = {
|
||||||
|
'MODEL_BUILDING': MODEL_BUILDING_ENABLED,
|
||||||
|
'CELERY': FLAG_CELERY_PRESENT,
|
||||||
|
'PLUGINS': PLUGINS_ENABLED,
|
||||||
|
'SENTRY': SENTRY_ENABLED,
|
||||||
|
'ENVIFORMER': ENVIFORMER_PRESENT,
|
||||||
|
'APPLICABILITY_DOMAIN': APPLICABILITY_DOMAIN_ENABLED,
|
||||||
|
}
|
||||||
|
|||||||
@ -1,40 +1,105 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from .models import User, Group, UserPackagePermission, GroupPackagePermission, Setting, SimpleAmbitRule, Scenario
|
from .models import (
|
||||||
|
User,
|
||||||
|
UserPackagePermission,
|
||||||
|
Group,
|
||||||
|
GroupPackagePermission,
|
||||||
|
Package,
|
||||||
|
MLRelativeReasoning,
|
||||||
|
Compound,
|
||||||
|
CompoundStructure,
|
||||||
|
SimpleAmbitRule,
|
||||||
|
ParallelRule,
|
||||||
|
Reaction,
|
||||||
|
Pathway,
|
||||||
|
Node,
|
||||||
|
Edge,
|
||||||
|
Scenario,
|
||||||
|
Setting
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(admin.ModelAdmin):
|
class UserAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GroupAdmin(admin.ModelAdmin):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class UserPackagePermissionAdmin(admin.ModelAdmin):
|
class UserPackagePermissionAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class GroupAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GroupPackagePermissionAdmin(admin.ModelAdmin):
|
class GroupPackagePermissionAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SettingAdmin(admin.ModelAdmin):
|
class EPAdmin(admin.ModelAdmin):
|
||||||
|
search_fields = ['name', 'description']
|
||||||
|
|
||||||
|
|
||||||
|
class PackageAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class MLRelativeReasoningAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class SimpleAmbitRuleAdmin(admin.ModelAdmin):
|
class CompoundAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class ScenarioAdmin(admin.ModelAdmin):
|
class CompoundStructureAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleAmbitRuleAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ParallelRuleAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ReactionAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class PathwayAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class NodeAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ScenarioAdmin(EPAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SettingAdmin(EPAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
admin.site.register(Group, GroupAdmin)
|
|
||||||
admin.site.register(UserPackagePermission, UserPackagePermissionAdmin)
|
admin.site.register(UserPackagePermission, UserPackagePermissionAdmin)
|
||||||
|
admin.site.register(Group, GroupAdmin)
|
||||||
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
admin.site.register(GroupPackagePermission, GroupPackagePermissionAdmin)
|
||||||
admin.site.register(Setting, SettingAdmin)
|
admin.site.register(Package, PackageAdmin)
|
||||||
|
admin.site.register(MLRelativeReasoning, MLRelativeReasoningAdmin)
|
||||||
|
admin.site.register(Compound, CompoundAdmin)
|
||||||
|
admin.site.register(CompoundStructure, CompoundStructureAdmin)
|
||||||
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
admin.site.register(SimpleAmbitRule, SimpleAmbitRuleAdmin)
|
||||||
|
admin.site.register(ParallelRule, ParallelRuleAdmin)
|
||||||
|
admin.site.register(Reaction, ReactionAdmin)
|
||||||
|
admin.site.register(Pathway, PathwayAdmin)
|
||||||
|
admin.site.register(Node, NodeAdmin)
|
||||||
|
admin.site.register(Edge, EdgeAdmin)
|
||||||
|
admin.site.register(Setting, SettingAdmin)
|
||||||
admin.site.register(Scenario, ScenarioAdmin)
|
admin.site.register(Scenario, ScenarioAdmin)
|
||||||
|
|||||||
@ -4,3 +4,6 @@ from django.apps import AppConfig
|
|||||||
class EPDBConfig(AppConfig):
|
class EPDBConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
name = 'epdb'
|
name = 'epdb'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import epdb.signals # noqa: F401
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class UserManager(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_user_by_id(user, user_uuid: str):
|
def get_user_by_id(user, user_uuid: str):
|
||||||
if user.uuid != user_uuid and not user.is_superuser:
|
if str(user.uuid) != user_uuid and not user.is_superuser:
|
||||||
raise ValueError("Getting user failed!")
|
raise ValueError("Getting user failed!")
|
||||||
return get_user_model().objects.get(uuid=user_uuid)
|
return get_user_model().objects.get(uuid=user_uuid)
|
||||||
|
|
||||||
@ -183,6 +183,25 @@ class PackageManager(object):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def administrable(user, package):
|
||||||
|
if UserPackagePermission.objects.filter(package=package, user=user, permission=Permission.ALL[0]).exists() or \
|
||||||
|
GroupPackagePermission.objects.filter(package=package, group__in=GroupManager.get_groups(user), permission=Permission.ALL[0]).exists() or \
|
||||||
|
user.is_superuser:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# @staticmethod
|
||||||
|
# def get_package_permission(user: 'User', package: Union[str, 'Package']):
|
||||||
|
# if PackageManager.administrable(user, package):
|
||||||
|
# return Permission.ALL[0]
|
||||||
|
# elif PackageManager.writable(user, package):
|
||||||
|
# return Permission.WRITE[0]
|
||||||
|
# elif PackageManager.readable(user, package):
|
||||||
|
# return Permission.READ[0]
|
||||||
|
# else:
|
||||||
|
# return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def has_package_permission(user: 'User', package: Union[str, 'Package'], permission: str):
|
def has_package_permission(user: 'User', package: Union[str, 'Package'], permission: str):
|
||||||
|
|
||||||
@ -339,7 +358,7 @@ class PackageManager(object):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def import_package(data: dict, owner: User, keep_ids=False):
|
def import_package(data: dict, owner: User, keep_ids=False, add_import_timestamp=True):
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
@ -349,7 +368,12 @@ class PackageManager(object):
|
|||||||
|
|
||||||
pack = Package()
|
pack = Package()
|
||||||
pack.uuid = UUID(data['id'].split('/')[-1]) if keep_ids else uuid4()
|
pack.uuid = UUID(data['id'].split('/')[-1]) if keep_ids else uuid4()
|
||||||
|
|
||||||
|
if add_import_timestamp:
|
||||||
pack.name = '{} - {}'.format(data['name'], datetime.now().strftime('%Y-%m-%d %H:%M'))
|
pack.name = '{} - {}'.format(data['name'], datetime.now().strftime('%Y-%m-%d %H:%M'))
|
||||||
|
else:
|
||||||
|
pack.name = data['name']
|
||||||
|
|
||||||
pack.reviewed = True if data['reviewStatus'] == 'reviewed' else False
|
pack.reviewed = True if data['reviewStatus'] == 'reviewed' else False
|
||||||
pack.description = data['description']
|
pack.description = data['description']
|
||||||
pack.save()
|
pack.save()
|
||||||
@ -890,9 +914,10 @@ class SearchManager(object):
|
|||||||
|
|
||||||
class SNode(object):
|
class SNode(object):
|
||||||
|
|
||||||
def __init__(self, smiles: str, depth: int):
|
def __init__(self, smiles: str, depth: int, app_domain_assessment: dict = None):
|
||||||
self.smiles = smiles
|
self.smiles = smiles
|
||||||
self.depth = depth
|
self.depth = depth
|
||||||
|
self.app_domain_assessment = app_domain_assessment
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash(self.smiles)
|
return hash(self.smiles)
|
||||||
@ -1035,7 +1060,7 @@ class SPathway(object):
|
|||||||
def depth(self):
|
def depth(self):
|
||||||
return max([v.depth for v in self.smiles_to_node.values()])
|
return max([v.depth for v in self.smiles_to_node.values()])
|
||||||
|
|
||||||
def _get_nodes_for_depth(self, depth: int):
|
def _get_nodes_for_depth(self, depth: int) -> List[SNode]:
|
||||||
if depth == 0:
|
if depth == 0:
|
||||||
return self.root_nodes
|
return self.root_nodes
|
||||||
|
|
||||||
@ -1046,7 +1071,7 @@ class SPathway(object):
|
|||||||
|
|
||||||
return sorted(res, key=lambda x: x.smiles)
|
return sorted(res, key=lambda x: x.smiles)
|
||||||
|
|
||||||
def _get_edges_for_depth(self, depth: int):
|
def _get_edges_for_depth(self, depth: int) -> List[SEdge]:
|
||||||
res = []
|
res = []
|
||||||
for e in self.edges:
|
for e in self.edges:
|
||||||
for n in e.educts:
|
for n in e.educts:
|
||||||
@ -1071,15 +1096,44 @@ class SPathway(object):
|
|||||||
new_tp = False
|
new_tp = False
|
||||||
if substrates:
|
if substrates:
|
||||||
for sub in substrates:
|
for sub in substrates:
|
||||||
|
|
||||||
|
if sub.app_domain_assessment is None:
|
||||||
|
if self.prediction_setting.model:
|
||||||
|
if self.prediction_setting.model.app_domain:
|
||||||
|
app_domain_assessment = self.prediction_setting.model.app_domain.assess(sub.smiles)[0]
|
||||||
|
|
||||||
|
if self.persist is not None:
|
||||||
|
n = self.snode_persist_lookup[sub]
|
||||||
|
|
||||||
|
assert n.id is not None, "Node has no id! Should have been saved already... aborting!"
|
||||||
|
node_data = n.simple_json()
|
||||||
|
node_data['image'] = f"{n.url}?image=svg"
|
||||||
|
app_domain_assessment['assessment']['node'] = node_data
|
||||||
|
|
||||||
|
n.kv['app_domain_assessment'] = app_domain_assessment
|
||||||
|
n.save()
|
||||||
|
|
||||||
|
sub.app_domain_assessment = app_domain_assessment
|
||||||
|
|
||||||
|
|
||||||
candidates = self.prediction_setting.expand(self, sub)
|
candidates = self.prediction_setting.expand(self, sub)
|
||||||
|
# candidates is a List of PredictionResult. The length of the List is equal to the number of rules
|
||||||
for cand_set in candidates:
|
for cand_set in candidates:
|
||||||
if cand_set:
|
if cand_set:
|
||||||
new_tp = True
|
new_tp = True
|
||||||
|
# cand_set is a PredictionResult object that can consist of multiple candidate reactions
|
||||||
for cand in cand_set:
|
for cand in cand_set:
|
||||||
cand_nodes = []
|
cand_nodes = []
|
||||||
|
# candidate reactions can have multiple fragments
|
||||||
for c in cand:
|
for c in cand:
|
||||||
if c not in self.smiles_to_node:
|
if c not in self.smiles_to_node:
|
||||||
self.smiles_to_node[c] = SNode(c, sub.depth + 1)
|
# For new nodes do an AppDomain Assessment if an AppDomain is attached
|
||||||
|
app_domain_assessment = None
|
||||||
|
if self.prediction_setting.model:
|
||||||
|
if self.prediction_setting.model.app_domain:
|
||||||
|
app_domain_assessment = self.prediction_setting.model.app_domain.assess(c)[0]
|
||||||
|
|
||||||
|
self.smiles_to_node[c] = SNode(c, sub.depth + 1, app_domain_assessment)
|
||||||
|
|
||||||
node = self.smiles_to_node[c]
|
node = self.smiles_to_node[c]
|
||||||
cand_nodes.append(node)
|
cand_nodes.append(node)
|
||||||
@ -1092,18 +1146,30 @@ class SPathway(object):
|
|||||||
if len(substrates) == 0 or from_node is not None:
|
if len(substrates) == 0 or from_node is not None:
|
||||||
self.done = True
|
self.done = True
|
||||||
|
|
||||||
# Check if we need to write back data to database
|
# Check if we need to write back data to the database
|
||||||
if new_tp and self.persist:
|
if new_tp and self.persist:
|
||||||
self._sync_to_pathway()
|
self._sync_to_pathway()
|
||||||
# call save to update internal modified field
|
# call save to update the internal modified field
|
||||||
self.persist.save()
|
self.persist.save()
|
||||||
|
|
||||||
def _sync_to_pathway(self):
|
def _sync_to_pathway(self) -> None:
|
||||||
logger.info("Updating Pathway with SPathway")
|
logger.info("Updating Pathway with SPathway")
|
||||||
|
|
||||||
for snode in self.smiles_to_node.values():
|
for snode in self.smiles_to_node.values():
|
||||||
if snode not in self.snode_persist_lookup:
|
if snode not in self.snode_persist_lookup:
|
||||||
n = Node.create(self.persist, snode.smiles, snode.depth)
|
n = Node.create(self.persist, snode.smiles, snode.depth)
|
||||||
|
|
||||||
|
if snode.app_domain_assessment is not None:
|
||||||
|
app_domain_assessment = snode.app_domain_assessment
|
||||||
|
|
||||||
|
assert n.id is not None, "Node has no id! Should have been saved already... aborting!"
|
||||||
|
node_data = n.simple_json()
|
||||||
|
node_data['image'] = f"{n.url}?image=svg"
|
||||||
|
app_domain_assessment['assessment']['node'] = node_data
|
||||||
|
|
||||||
|
n.kv['app_domain_assessment'] = app_domain_assessment
|
||||||
|
n.save()
|
||||||
|
|
||||||
self.snode_persist_lookup[snode] = n
|
self.snode_persist_lookup[snode] = n
|
||||||
|
|
||||||
for sedge in self.edges:
|
for sedge in self.edges:
|
||||||
@ -1125,7 +1191,6 @@ class SPathway(object):
|
|||||||
self.sedge_persist_lookup[sedge] = e
|
self.sedge_persist_lookup[sedge] = e
|
||||||
|
|
||||||
logger.info("Update done!")
|
logger.info("Update done!")
|
||||||
pass
|
|
||||||
|
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
nodes = []
|
nodes = []
|
||||||
|
|||||||
@ -5,7 +5,7 @@ from django.core.management.base import BaseCommand
|
|||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
from epdb.logic import UserManager, GroupManager, PackageManager, SettingManager
|
from epdb.logic import UserManager, GroupManager, PackageManager, SettingManager
|
||||||
from epdb.models import UserSettingPermission, MLRelativeReasoning, EnviFormer, Permission, User
|
from epdb.models import UserSettingPermission, MLRelativeReasoning, EnviFormer, Permission, User, ExternalDatabase
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@ -58,7 +58,7 @@ class Command(BaseCommand):
|
|||||||
return anon, admin, g, jebus
|
return anon, admin, g, jebus
|
||||||
|
|
||||||
def import_package(self, data, owner):
|
def import_package(self, data, owner):
|
||||||
return PackageManager.import_package(data, owner, keep_ids=True)
|
return PackageManager.import_package(data, owner, keep_ids=True, add_import_timestamp=False)
|
||||||
|
|
||||||
def create_default_setting(self, owner, packages):
|
def create_default_setting(self, owner, packages):
|
||||||
s = SettingManager.create_setting(
|
s = SettingManager.create_setting(
|
||||||
@ -74,6 +74,76 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def populate_common_external_databases(self):
|
||||||
|
"""
|
||||||
|
Helper function to populate common external databases.
|
||||||
|
This can be called from a Django management command.
|
||||||
|
"""
|
||||||
|
databases = [
|
||||||
|
{
|
||||||
|
'name': 'PubChem Compound',
|
||||||
|
'full_name': 'PubChem Compound Database',
|
||||||
|
'description': 'Chemical database of small organic molecules',
|
||||||
|
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
|
||||||
|
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/compound/{id}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'PubChem Substance',
|
||||||
|
'full_name': 'PubChem Substance Database',
|
||||||
|
'description': 'Database of chemical substances',
|
||||||
|
'base_url': 'https://pubchem.ncbi.nlm.nih.gov',
|
||||||
|
'url_pattern': 'https://pubchem.ncbi.nlm.nih.gov/substance/{id}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'ChEBI',
|
||||||
|
'full_name': 'Chemical Entities of Biological Interest',
|
||||||
|
'description': 'Dictionary of molecular entities',
|
||||||
|
'base_url': 'https://www.ebi.ac.uk/chebi',
|
||||||
|
'url_pattern': 'https://www.ebi.ac.uk/chebi/searchId.do?chebiId=CHEBI:{id}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'RHEA',
|
||||||
|
'full_name': 'RHEA Reaction Database',
|
||||||
|
'description': 'Comprehensive resource of biochemical reactions',
|
||||||
|
'base_url': 'https://www.rhea-db.org',
|
||||||
|
'url_pattern': 'https://www.rhea-db.org/rhea/{id}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'CAS',
|
||||||
|
'full_name': 'Chemical Abstracts Service Registry',
|
||||||
|
'description': 'Registry of chemical substances',
|
||||||
|
'base_url': 'https://www.cas.org',
|
||||||
|
'url_pattern': None # CAS doesn't have a free public URL pattern
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'KEGG Reaction',
|
||||||
|
'full_name': 'KEGG Reaction Database',
|
||||||
|
'description': 'Database of biochemical reactions',
|
||||||
|
'base_url': 'https://www.genome.jp',
|
||||||
|
'url_pattern': 'https://www.genome.jp/entry/reaction+{id}'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'MetaCyc',
|
||||||
|
'full_name': 'MetaCyc Metabolic Pathway Database',
|
||||||
|
'description': 'Database of metabolic pathways and enzymes',
|
||||||
|
'base_url': 'https://metacyc.org',
|
||||||
|
'url_pattern': None
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'UniProt',
|
||||||
|
'full_name': 'MetaCyc Metabolic Pathway Database',
|
||||||
|
'description': 'UniProt is a freely accessible database of protein sequence and functional information',
|
||||||
|
'base_url': 'https://www.uniprot.org',
|
||||||
|
'url_pattern': 'https://www.uniprot.org/uniprotkb?query="{id}"'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
for db_info in databases:
|
||||||
|
ExternalDatabase.objects.get_or_create(
|
||||||
|
name=db_info['name'],
|
||||||
|
defaults=db_info
|
||||||
|
)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
# Create users
|
# Create users
|
||||||
@ -117,17 +187,17 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
# Create RR
|
# Create RR
|
||||||
ml_model = MLRelativeReasoning.create(
|
ml_model = MLRelativeReasoning.create(
|
||||||
pack,
|
package=pack,
|
||||||
'ECC - BBD - T0.5',
|
rule_packages=[mapping['EAWAG-BBD']],
|
||||||
'ML Relative Reasoning',
|
data_packages=[mapping['EAWAG-BBD']],
|
||||||
[mapping['EAWAG-BBD']],
|
eval_packages=[],
|
||||||
[mapping['EAWAG-BBD']],
|
threshold=0.5,
|
||||||
[],
|
name='ECC - BBD - T0.5',
|
||||||
0.5
|
description='ML Relative Reasoning',
|
||||||
)
|
)
|
||||||
|
|
||||||
X, y = ml_model.build_dataset()
|
ml_model.build_dataset()
|
||||||
ml_model.build_model(X, y)
|
ml_model.build_model()
|
||||||
# ml_model.evaluate_model()
|
# ml_model.evaluate_model()
|
||||||
|
|
||||||
# If available create EnviFormerModel
|
# If available create EnviFormerModel
|
||||||
|
|||||||
1110
epdb/models.py
1110
epdb/models.py
File diff suppressed because it is too large
Load Diff
20
epdb/signals.py
Normal file
20
epdb/signals.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from django.db import transaction
|
||||||
|
from django.db.models.signals import pre_delete
|
||||||
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
from epdb.models import Node, Edge
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(pre_delete, sender=Node)
|
||||||
|
@transaction.atomic
|
||||||
|
def delete_orphan_edges(sender, instance, **kwargs):
|
||||||
|
# check if the node that is about to be deleted is the only start node
|
||||||
|
for edge in Edge.objects.filter(start_nodes=instance):
|
||||||
|
if edge.start_nodes.count() == 1:
|
||||||
|
edge.delete()
|
||||||
|
|
||||||
|
# same for end_nodes
|
||||||
|
for edge in Edge.objects.filter(end_nodes=instance):
|
||||||
|
# check if the node that is about to be deleted is the only start node
|
||||||
|
if edge.end_nodes.count() == 1:
|
||||||
|
edge.delete()
|
||||||
@ -31,8 +31,8 @@ def send_registration_mail(user_pk: int):
|
|||||||
@shared_task(queue='model')
|
@shared_task(queue='model')
|
||||||
def build_model(model_pk: int):
|
def build_model(model_pk: int):
|
||||||
mod = EPModel.objects.get(id=model_pk)
|
mod = EPModel.objects.get(id=model_pk)
|
||||||
X, y = mod.build_dataset()
|
mod.build_dataset()
|
||||||
mod.build_model(X, y)
|
mod.build_model()
|
||||||
|
|
||||||
|
|
||||||
@shared_task(queue='model')
|
@shared_task(queue='model')
|
||||||
@ -58,7 +58,7 @@ def predict(pw_pk: int, pred_setting_pk: int, limit: Optional[int] = None, node_
|
|||||||
spw.predict_step(from_depth=level)
|
spw.predict_step(from_depth=level)
|
||||||
level += 1
|
level += 1
|
||||||
|
|
||||||
# break in case we are in incremental model
|
# break in case we are in incremental mode
|
||||||
if limit != -1:
|
if limit != -1:
|
||||||
if level >= limit:
|
if level >= limit:
|
||||||
break
|
break
|
||||||
|
|||||||
280
epdb/views.py
280
epdb/views.py
@ -4,6 +4,9 @@ from typing import List, Dict, Any
|
|||||||
|
|
||||||
from django.conf import settings as s
|
from django.conf import settings as s
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db.models import F, Value
|
||||||
|
from django.db.models.fields import CharField
|
||||||
|
from django.db.models.functions import Concat
|
||||||
from django.http import JsonResponse, HttpResponse, HttpResponseNotAllowed, HttpResponseBadRequest
|
from django.http import JsonResponse, HttpResponse, HttpResponseNotAllowed, HttpResponseBadRequest
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
@ -103,7 +106,10 @@ def login(request):
|
|||||||
else:
|
else:
|
||||||
context['message'] = "Account has been created! You'll receive a mail to activate your account shortly."
|
context['message'] = "Account has been created! You'll receive a mail to activate your account shortly."
|
||||||
return render(request, 'login.html', context)
|
return render(request, 'login.html', context)
|
||||||
|
else:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
else:
|
||||||
|
return HttpResponseNotAllowed(['GET', 'POST'])
|
||||||
|
|
||||||
def logout(request):
|
def logout(request):
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
@ -136,7 +142,7 @@ def editable(request, user):
|
|||||||
f"{s.SERVER_URL}/group", f"{s.SERVER_URL}/search"]:
|
f"{s.SERVER_URL}/group", f"{s.SERVER_URL}/search"]:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
print(f"Unknown url: {url}")
|
logger.debug(f"Unknown url: {url}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -158,7 +164,7 @@ def get_base_context(request, for_user=None) -> Dict[str, Any]:
|
|||||||
'writeable_packages': PackageManager.get_all_writeable_packages(current_user),
|
'writeable_packages': PackageManager.get_all_writeable_packages(current_user),
|
||||||
'available_groups': GroupManager.get_groups(current_user),
|
'available_groups': GroupManager.get_groups(current_user),
|
||||||
'available_settings': SettingManager.get_all_settings(current_user),
|
'available_settings': SettingManager.get_all_settings(current_user),
|
||||||
'enabled_features': [],
|
'enabled_features': s.FLAGS,
|
||||||
'debug': s.DEBUG,
|
'debug': s.DEBUG,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -196,6 +202,15 @@ def breadcrumbs(first_level_object=None, second_level_namespace=None, second_lev
|
|||||||
return bread
|
return bread
|
||||||
|
|
||||||
|
|
||||||
|
def set_scenarios(current_user, attach_object, scenario_urls: List[str]):
|
||||||
|
scens = []
|
||||||
|
for scenario_url in scenario_urls:
|
||||||
|
package = PackageManager.get_package_by_url(current_user, scenario_url)
|
||||||
|
scen = Scenario.objects.get(package=package, uuid=scenario_url.split('/')[-1])
|
||||||
|
scens.append(scen)
|
||||||
|
|
||||||
|
attach_object.set_scenarios(scens)
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = 'enviPath - Home'
|
context['title'] = 'enviPath - Home'
|
||||||
@ -424,8 +439,16 @@ def scenarios(request):
|
|||||||
if request.GET.get('all'):
|
if request.GET.get('all'):
|
||||||
return JsonResponse({
|
return JsonResponse({
|
||||||
"objects": [
|
"objects": [
|
||||||
{"name": pw.name, "url": pw.url, "reviewed": True}
|
{"name": s.name, "url": s.full_url, "reviewed": True}
|
||||||
for pw in reviewed_scenario_qs
|
for s in reviewed_scenario_qs.annotate(
|
||||||
|
full_url=Concat(
|
||||||
|
Value(s.SERVER_URL + '/package/'),
|
||||||
|
F("package__uuid"),
|
||||||
|
Value("/scenario/"),
|
||||||
|
F("uuid"),
|
||||||
|
output_field=CharField(),
|
||||||
|
)
|
||||||
|
)
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -505,6 +528,7 @@ def search(request):
|
|||||||
packages = PackageManager.get_reviewed_packages()
|
packages = PackageManager.get_reviewed_packages()
|
||||||
|
|
||||||
search_result = SearchManager.search(packages, searchterm, mode)
|
search_result = SearchManager.search(packages, searchterm, mode)
|
||||||
|
|
||||||
return JsonResponse(search_result, safe=False)
|
return JsonResponse(search_result, safe=False)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
@ -530,6 +554,7 @@ def search(request):
|
|||||||
packages = PackageManager.get_reviewed_packages()
|
packages = PackageManager.get_reviewed_packages()
|
||||||
|
|
||||||
context['search_result'] = SearchManager.search(packages, searchterm, mode)
|
context['search_result'] = SearchManager.search(packages, searchterm, mode)
|
||||||
|
context['search_result']['searchterm'] = searchterm
|
||||||
|
|
||||||
return render(request, 'search.html', context)
|
return render(request, 'search.html', context)
|
||||||
|
|
||||||
@ -572,15 +597,21 @@ def package_models(request, package_uuid):
|
|||||||
context['model_types'] = {
|
context['model_types'] = {
|
||||||
'ML Relative Reasoning': 'ml-relative-reasoning',
|
'ML Relative Reasoning': 'ml-relative-reasoning',
|
||||||
'Rule Based Relative Reasoning': 'rule-based-relative-reasoning',
|
'Rule Based Relative Reasoning': 'rule-based-relative-reasoning',
|
||||||
'EnviFormer': 'enviformer',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.FLAGS.get('ENVIFORMER', False):
|
||||||
|
context['model_types']['EnviFormer'] = 'enviformer'
|
||||||
|
|
||||||
|
if s.FLAGS.get('PLUGINS', False):
|
||||||
for k, v in s.CLASSIFIER_PLUGINS.items():
|
for k, v in s.CLASSIFIER_PLUGINS.items():
|
||||||
context['model_types'][v.display()] = k
|
context['model_types'][v.display()] = k
|
||||||
|
|
||||||
return render(request, 'collections/objects_list.html', context)
|
return render(request, 'collections/objects_list.html', context)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
|
|
||||||
|
log_post_params(request)
|
||||||
|
|
||||||
name = request.POST.get('model-name')
|
name = request.POST.get('model-name')
|
||||||
description = request.POST.get('model-description')
|
description = request.POST.get('model-description')
|
||||||
|
|
||||||
@ -603,14 +634,25 @@ def package_models(request, package_uuid):
|
|||||||
data_package_objs = [PackageManager.get_package_by_url(current_user, p) for p in data_packages]
|
data_package_objs = [PackageManager.get_package_by_url(current_user, p) for p in data_packages]
|
||||||
eval_packages_objs = [PackageManager.get_package_by_url(current_user, p) for p in eval_packages]
|
eval_packages_objs = [PackageManager.get_package_by_url(current_user, p) for p in eval_packages]
|
||||||
|
|
||||||
|
# App Domain related parameters
|
||||||
|
build_ad = request.POST.get('build-app-domain', False) == 'on'
|
||||||
|
num_neighbors = request.POST.get('num-neighbors', 5)
|
||||||
|
reliability_threshold = request.POST.get('reliability-threshold', 0.5)
|
||||||
|
local_compatibility_threshold = request.POST.get('local-compatibility-threshold', 0.5)
|
||||||
|
|
||||||
mod = MLRelativeReasoning.create(
|
mod = MLRelativeReasoning.create(
|
||||||
current_package,
|
package=current_package,
|
||||||
name,
|
name=name,
|
||||||
description,
|
description=description,
|
||||||
rule_package_objs,
|
rule_packages=rule_package_objs,
|
||||||
data_package_objs,
|
data_packages=data_package_objs,
|
||||||
eval_packages_objs,
|
eval_packages=eval_packages_objs,
|
||||||
threshold
|
threshold=threshold,
|
||||||
|
# fingerprinter=fingerprinter,
|
||||||
|
build_app_domain=build_ad,
|
||||||
|
app_domain_num_neighbours=num_neighbors,
|
||||||
|
app_domain_reliability_threshold=reliability_threshold,
|
||||||
|
app_domain_local_compatibility_threshold=local_compatibility_threshold,
|
||||||
)
|
)
|
||||||
|
|
||||||
from .tasks import build_model
|
from .tasks import build_model
|
||||||
@ -646,7 +688,7 @@ def package_model(request, package_uuid, model_uuid):
|
|||||||
if len(pr) > 0:
|
if len(pr) > 0:
|
||||||
products = []
|
products = []
|
||||||
for prod_set in pr.product_sets:
|
for prod_set in pr.product_sets:
|
||||||
print(f"Checking {prod_set}")
|
logger.debug(f"Checking {prod_set}")
|
||||||
products.append(tuple([x for x in prod_set]))
|
products.append(tuple([x for x in prod_set]))
|
||||||
|
|
||||||
res.append({
|
res.append({
|
||||||
@ -657,6 +699,12 @@ def package_model(request, package_uuid, model_uuid):
|
|||||||
|
|
||||||
return JsonResponse(res, safe=False)
|
return JsonResponse(res, safe=False)
|
||||||
|
|
||||||
|
elif request.GET.get('app-domain-assessment', False):
|
||||||
|
smiles = request.GET['smiles']
|
||||||
|
stand_smiles = FormatConverter.standardize(smiles)
|
||||||
|
app_domain_assessment = current_model.app_domain.assess(stand_smiles)[0]
|
||||||
|
return JsonResponse(app_domain_assessment, safe=False)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = f'enviPath - {current_package.name} - {current_model.name}'
|
context['title'] = f'enviPath - {current_package.name} - {current_model.name}'
|
||||||
|
|
||||||
@ -665,12 +713,13 @@ def package_model(request, package_uuid, model_uuid):
|
|||||||
context['breadcrumbs'] = breadcrumbs(current_package, 'model', current_model)
|
context['breadcrumbs'] = breadcrumbs(current_package, 'model', current_model)
|
||||||
|
|
||||||
context['model'] = current_model
|
context['model'] = current_model
|
||||||
|
context['current_object'] = current_model
|
||||||
|
|
||||||
return render(request, 'objects/model.html', context)
|
return render(request, 'objects/model.html', context)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-model':
|
if hidden == 'delete':
|
||||||
current_model.delete()
|
current_model.delete()
|
||||||
return redirect(current_package.url + '/model')
|
return redirect(current_package.url + '/model')
|
||||||
else:
|
else:
|
||||||
@ -696,8 +745,6 @@ def package(request, package_uuid):
|
|||||||
context['breadcrumbs'] = breadcrumbs(current_package)
|
context['breadcrumbs'] = breadcrumbs(current_package)
|
||||||
|
|
||||||
context['package'] = current_package
|
context['package'] = current_package
|
||||||
# context['package_group'] = GroupPackagePermission.objects.filter(package=current_package,
|
|
||||||
# permission=GroupPackagePermission.ALL)
|
|
||||||
|
|
||||||
user_perms = UserPackagePermission.objects.filter(package=current_package)
|
user_perms = UserPackagePermission.objects.filter(package=current_package)
|
||||||
users = get_user_model().objects.exclude(
|
users = get_user_model().objects.exclude(
|
||||||
@ -716,14 +763,16 @@ def package(request, package_uuid):
|
|||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
|
|
||||||
if s.DEBUG:
|
log_post_params(request)
|
||||||
for k, v in request.POST.items():
|
|
||||||
logger.debug(f"{k}\t{v}")
|
|
||||||
|
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-package':
|
if hidden == 'delete':
|
||||||
logger.debug(current_package.delete())
|
logger.debug(current_package.delete())
|
||||||
return redirect(s.SERVER_URL + '/package')
|
return redirect(s.SERVER_URL + '/package')
|
||||||
|
elif hidden == 'publish-package':
|
||||||
|
for g in Group.objects.filter(public=True):
|
||||||
|
PackageManager.update_permissions(current_user, current_package, g, Permission.READ[0])
|
||||||
|
return redirect(current_package.url)
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
@ -855,17 +904,24 @@ def package_compound(request, package_uuid, compound_uuid):
|
|||||||
context['breadcrumbs'] = breadcrumbs(current_package, 'compound', current_compound)
|
context['breadcrumbs'] = breadcrumbs(current_package, 'compound', current_compound)
|
||||||
|
|
||||||
context['compound'] = current_compound
|
context['compound'] = current_compound
|
||||||
|
context['current_object'] = current_compound
|
||||||
|
|
||||||
return render(request, 'objects/compound.html', context)
|
return render(request, 'objects/compound.html', context)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-compound':
|
if hidden == 'delete':
|
||||||
current_compound.delete()
|
current_compound.delete()
|
||||||
return redirect(current_package.url + '/compound')
|
return redirect(current_package.url + '/compound')
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_compound, selected_scenarios)
|
||||||
|
return redirect(current_compound.url)
|
||||||
|
|
||||||
new_compound_name = request.POST.get('compound-name')
|
new_compound_name = request.POST.get('compound-name')
|
||||||
new_compound_description = request.POST.get('compound-description')
|
new_compound_description = request.POST.get('compound-description')
|
||||||
|
|
||||||
@ -897,6 +953,7 @@ def package_compound_structures(request, package_uuid, compound_uuid):
|
|||||||
|
|
||||||
context['meta']['current_package'] = current_package
|
context['meta']['current_package'] = current_package
|
||||||
context['object_type'] = 'structure'
|
context['object_type'] = 'structure'
|
||||||
|
context['breadcrumbs'] = breadcrumbs(current_package, 'compound', current_compound, 'structure')
|
||||||
|
|
||||||
reviewed_compound_structure_qs = CompoundStructure.objects.none()
|
reviewed_compound_structure_qs = CompoundStructure.objects.none()
|
||||||
unreviewed_compound_structure_qs = CompoundStructure.objects.none()
|
unreviewed_compound_structure_qs = CompoundStructure.objects.none()
|
||||||
@ -936,12 +993,45 @@ def package_compound_structure(request, package_uuid, compound_uuid, structure_u
|
|||||||
context['title'] = f'enviPath - {current_package.name} - {current_compound.name} - {current_structure.name}'
|
context['title'] = f'enviPath - {current_package.name} - {current_compound.name} - {current_structure.name}'
|
||||||
|
|
||||||
context['meta']['current_package'] = current_package
|
context['meta']['current_package'] = current_package
|
||||||
context['object_type'] = 'compound'
|
context['object_type'] = 'structure'
|
||||||
|
|
||||||
context['compound_structure'] = current_structure
|
context['compound_structure'] = current_structure
|
||||||
|
context['current_object'] = current_structure
|
||||||
|
context['breadcrumbs'] = breadcrumbs(current_package, 'compound', current_compound, 'structure', current_structure)
|
||||||
|
|
||||||
return render(request, 'objects/compound_structure.html', context)
|
return render(request, 'objects/compound_structure.html', context)
|
||||||
|
|
||||||
|
elif request.method == 'POST':
|
||||||
|
|
||||||
|
if hidden := request.POST.get('hidden', None):
|
||||||
|
if hidden == 'delete':
|
||||||
|
# Check if we have to delete the compound as no structure is left
|
||||||
|
if len(current_structure.compound.structures.all()) == 1:
|
||||||
|
# This will delete the structure as well
|
||||||
|
current_compound.delete()
|
||||||
|
return redirect(current_package.url + '/compound')
|
||||||
|
else:
|
||||||
|
if current_structure.normalized_structure:
|
||||||
|
current_compound.delete()
|
||||||
|
return redirect(current_package.url + '/compound')
|
||||||
|
else:
|
||||||
|
if current_compound.default_structure == current_structure:
|
||||||
|
current_structure.delete()
|
||||||
|
current_compound.default_structure = current_compound.structures.all().first()
|
||||||
|
return redirect(current_compound.url + '/structure')
|
||||||
|
else:
|
||||||
|
current_structure.delete()
|
||||||
|
return redirect(current_compound.url + '/structure')
|
||||||
|
else:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_structure, selected_scenarios)
|
||||||
|
return redirect(current_structure.url)
|
||||||
|
|
||||||
|
return HttpResponseBadRequest()
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotAllowed(['GET', ])
|
return HttpResponseNotAllowed(['GET', ])
|
||||||
|
|
||||||
@ -1022,6 +1112,24 @@ def package_rule(request, package_uuid, rule_uuid):
|
|||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
|
|
||||||
|
if smiles := request.GET.get('smiles', False):
|
||||||
|
stand_smiles = FormatConverter.standardize(smiles)
|
||||||
|
res = current_rule.apply(stand_smiles)
|
||||||
|
if len(res) > 1:
|
||||||
|
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]))}"
|
||||||
|
# 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}
|
||||||
|
return HttpResponse(
|
||||||
|
IndigoUtils.smirks_to_svg(smirks, False, 0, 0,
|
||||||
|
educt_functional_groups=educt_functional_groups,
|
||||||
|
product_functional_groups=product_functional_groups),
|
||||||
|
content_type='image/svg+xml')
|
||||||
|
|
||||||
context['title'] = f'enviPath - {current_package.name} - {current_rule.name}'
|
context['title'] = f'enviPath - {current_package.name} - {current_rule.name}'
|
||||||
|
|
||||||
context['meta']['current_package'] = current_package
|
context['meta']['current_package'] = current_package
|
||||||
@ -1029,6 +1137,8 @@ def package_rule(request, package_uuid, rule_uuid):
|
|||||||
context['breadcrumbs'] = breadcrumbs(current_package, 'rule', current_rule)
|
context['breadcrumbs'] = breadcrumbs(current_package, 'rule', current_rule)
|
||||||
|
|
||||||
context['rule'] = current_rule
|
context['rule'] = current_rule
|
||||||
|
context['current_object'] = current_rule
|
||||||
|
|
||||||
if isinstance(current_rule, SimpleAmbitRule):
|
if isinstance(current_rule, SimpleAmbitRule):
|
||||||
return render(request, 'objects/simple_rule.html', context)
|
return render(request, 'objects/simple_rule.html', context)
|
||||||
else: # isinstance(current_rule, ParallelRule) or isinstance(current_rule, SequentialRule):
|
else: # isinstance(current_rule, ParallelRule) or isinstance(current_rule, SequentialRule):
|
||||||
@ -1036,12 +1146,18 @@ def package_rule(request, package_uuid, rule_uuid):
|
|||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-rule':
|
if hidden == 'delete':
|
||||||
current_rule.delete()
|
current_rule.delete()
|
||||||
return redirect(current_package.url + '/rule')
|
return redirect(current_package.url + '/rule')
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_rule, selected_scenarios)
|
||||||
|
return redirect(current_rule.url)
|
||||||
|
|
||||||
rule_name = request.POST.get('rule-name', '').strip()
|
rule_name = request.POST.get('rule-name', '').strip()
|
||||||
rule_description = request.POST.get('rule-description', '').strip()
|
rule_description = request.POST.get('rule-description', '').strip()
|
||||||
|
|
||||||
@ -1127,17 +1243,24 @@ def package_reaction(request, package_uuid, reaction_uuid):
|
|||||||
context['breadcrumbs'] = breadcrumbs(current_package, 'reaction', current_reaction)
|
context['breadcrumbs'] = breadcrumbs(current_package, 'reaction', current_reaction)
|
||||||
|
|
||||||
context['reaction'] = current_reaction
|
context['reaction'] = current_reaction
|
||||||
|
context['current_object'] = current_reaction
|
||||||
|
|
||||||
return render(request, 'objects/reaction.html', context)
|
return render(request, 'objects/reaction.html', context)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-reaction':
|
if hidden == 'delete':
|
||||||
current_reaction.delete()
|
current_reaction.delete()
|
||||||
return redirect(current_package.url + '/reaction')
|
return redirect(current_package.url + '/reaction')
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_reaction, selected_scenarios)
|
||||||
|
return redirect(current_reaction.url)
|
||||||
|
|
||||||
new_reaction_name = request.POST.get('reaction-name')
|
new_reaction_name = request.POST.get('reaction-name')
|
||||||
new_reaction_description = request.POST.get('reaction-description')
|
new_reaction_description = request.POST.get('reaction-description')
|
||||||
|
|
||||||
@ -1195,8 +1318,8 @@ def package_pathways(request, package_uuid):
|
|||||||
|
|
||||||
log_post_params(request)
|
log_post_params(request)
|
||||||
|
|
||||||
name = request.POST.get('name', 'Pathway ' + str(Pathway.objects.filter(package=current_package).count()))
|
name = request.POST.get('name')
|
||||||
description = request.POST.get('description', s.DEFAULT_VALUES['description'])
|
description = request.POST.get('description')
|
||||||
pw_mode = request.POST.get('predict', 'predict')
|
pw_mode = request.POST.get('predict', 'predict')
|
||||||
smiles = request.POST.get('smiles')
|
smiles = request.POST.get('smiles')
|
||||||
|
|
||||||
@ -1217,7 +1340,14 @@ def package_pathways(request, package_uuid):
|
|||||||
return error(request, "Pathway prediction failed!",
|
return error(request, "Pathway prediction failed!",
|
||||||
f'Pathway prediction failed as received mode "{pw_mode}" is none of {modes}')
|
f'Pathway prediction failed as received mode "{pw_mode}" is none of {modes}')
|
||||||
|
|
||||||
|
prediction_setting = request.POST.get('prediction-setting', None)
|
||||||
|
if prediction_setting:
|
||||||
|
prediction_setting = SettingManager.get_setting_by_url(current_user, prediction_setting)
|
||||||
|
else:
|
||||||
|
prediction_setting = current_user.prediction_settings()
|
||||||
|
|
||||||
pw = Pathway.create(current_package, stand_smiles, name=name, description=description)
|
pw = Pathway.create(current_package, stand_smiles, name=name, description=description)
|
||||||
|
|
||||||
# set mode
|
# set mode
|
||||||
pw.kv.update({'mode': pw_mode})
|
pw.kv.update({'mode': pw_mode})
|
||||||
pw.save()
|
pw.save()
|
||||||
@ -1230,12 +1360,11 @@ def package_pathways(request, package_uuid):
|
|||||||
if pw_mode == 'incremental':
|
if pw_mode == 'incremental':
|
||||||
limit = 1
|
limit = 1
|
||||||
|
|
||||||
pred_setting = current_user.prediction_settings()
|
pw.setting = prediction_setting
|
||||||
pw.setting = pred_setting
|
|
||||||
pw.save()
|
pw.save()
|
||||||
|
|
||||||
from .tasks import predict
|
from .tasks import predict
|
||||||
predict.delay(pw.pk, pred_setting.pk, limit=limit)
|
predict.delay(pw.pk, prediction_setting.pk, limit=limit)
|
||||||
|
|
||||||
return redirect(pw.url)
|
return redirect(pw.url)
|
||||||
|
|
||||||
@ -1254,6 +1383,14 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
if request.GET.get("last_modified", False):
|
if request.GET.get("last_modified", False):
|
||||||
return JsonResponse({'modified': current_pathway.modified.strftime('%Y-%m-%d %H:%M:%S')})
|
return JsonResponse({'modified': current_pathway.modified.strftime('%Y-%m-%d %H:%M:%S')})
|
||||||
|
|
||||||
|
if request.GET.get("download", False) == "true":
|
||||||
|
filename = f"{current_pathway.name.replace(' ', '_')}_{current_pathway.uuid}.csv"
|
||||||
|
csv_pw = current_pathway.to_csv()
|
||||||
|
response = HttpResponse(csv_pw, content_type='text/csv')
|
||||||
|
response['Content-Disposition'] = f'attachment; filename="{filename}"'
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = f'enviPath - {current_package.name} - {current_pathway.name}'
|
context['title'] = f'enviPath - {current_package.name} - {current_pathway.name}'
|
||||||
|
|
||||||
@ -1262,6 +1399,7 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
context['breadcrumbs'] = breadcrumbs(current_package, 'pathway', current_pathway)
|
context['breadcrumbs'] = breadcrumbs(current_package, 'pathway', current_pathway)
|
||||||
|
|
||||||
context['pathway'] = current_pathway
|
context['pathway'] = current_pathway
|
||||||
|
context['current_object'] = current_pathway
|
||||||
|
|
||||||
context['breadcrumbs'] = [
|
context['breadcrumbs'] = [
|
||||||
{'Home': s.SERVER_URL},
|
{'Home': s.SERVER_URL},
|
||||||
@ -1276,12 +1414,18 @@ def package_pathway(request, package_uuid, pathway_uuid):
|
|||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-pathway':
|
if hidden == 'delete':
|
||||||
current_pathway.delete()
|
current_pathway.delete()
|
||||||
return redirect(current_package.url + '/pathway')
|
return redirect(current_package.url + '/pathway')
|
||||||
else:
|
else:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_pathway, selected_scenarios)
|
||||||
|
return redirect(current_pathway.url)
|
||||||
|
|
||||||
pathway_name = request.POST.get('pathway-name')
|
pathway_name = request.POST.get('pathway-name')
|
||||||
pathway_description = request.POST.get('pathway-description')
|
pathway_description = request.POST.get('pathway-description')
|
||||||
|
|
||||||
@ -1402,19 +1546,33 @@ def package_pathway_node(request, package_uuid, pathway_uuid, node_uuid):
|
|||||||
]
|
]
|
||||||
|
|
||||||
context['node'] = current_node
|
context['node'] = current_node
|
||||||
|
context['current_object'] = current_node
|
||||||
|
|
||||||
|
context['app_domain_assessment_data'] = json.dumps(current_node.get_app_domain_assessment_data())
|
||||||
|
|
||||||
return render(request, 'objects/node.html', context)
|
return render(request, 'objects/node.html', context)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if s.DEBUG:
|
|
||||||
for k, v in request.POST.items():
|
log_post_params(request)
|
||||||
print(k, v)
|
|
||||||
|
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-node':
|
if hidden == 'delete':
|
||||||
current_node.delete()
|
|
||||||
return redirect(current_pathway.url)
|
|
||||||
|
|
||||||
|
# pre_delete signal will take care of edge deletion
|
||||||
|
current_node.delete()
|
||||||
|
|
||||||
|
return redirect(current_pathway.url)
|
||||||
|
else:
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_node, selected_scenarios)
|
||||||
|
return redirect(current_node.url)
|
||||||
|
|
||||||
|
return HttpResponseBadRequest()
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotAllowed(['GET', 'POST'])
|
return HttpResponseNotAllowed(['GET', 'POST'])
|
||||||
|
|
||||||
@ -1463,6 +1621,8 @@ def package_pathway_edges(request, package_uuid, pathway_uuid):
|
|||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
|
|
||||||
|
log_post_params(request)
|
||||||
|
|
||||||
edge_name = request.POST.get('edge-name')
|
edge_name = request.POST.get('edge-name')
|
||||||
edge_description = request.POST.get('edge-description')
|
edge_description = request.POST.get('edge-description')
|
||||||
edge_substrates = request.POST.getlist('edge-substrates')
|
edge_substrates = request.POST.getlist('edge-substrates')
|
||||||
@ -1499,22 +1659,30 @@ def package_pathway_edge(request, package_uuid, pathway_uuid, edge_uuid):
|
|||||||
'title'] = f'enviPath - {current_package.name} - {current_pathway.name} - {current_edge.edge_label.name}'
|
'title'] = f'enviPath - {current_package.name} - {current_pathway.name} - {current_edge.edge_label.name}'
|
||||||
|
|
||||||
context['meta']['current_package'] = current_package
|
context['meta']['current_package'] = current_package
|
||||||
context['object_type'] = 'reaction'
|
context['object_type'] = 'edge'
|
||||||
context['breadcrumbs'] = breadcrumbs(current_package, 'pathway', current_pathway, 'edge', current_edge)
|
context['breadcrumbs'] = breadcrumbs(current_package, 'pathway', current_pathway, 'edge', current_edge)
|
||||||
context['edge'] = current_edge
|
context['edge'] = current_edge
|
||||||
|
context['current_object'] = current_edge
|
||||||
|
|
||||||
return render(request, 'objects/edge.html', context)
|
return render(request, 'objects/edge.html', context)
|
||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if s.DEBUG:
|
|
||||||
for k, v in request.POST.items():
|
log_post_params(request)
|
||||||
print(k, v)
|
|
||||||
|
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-edge':
|
if hidden == 'delete':
|
||||||
current_edge.delete()
|
current_edge.delete()
|
||||||
return redirect(current_pathway.url)
|
return redirect(current_pathway.url)
|
||||||
|
|
||||||
|
selected_scenarios = request.POST.getlist('selected-scenarios')
|
||||||
|
|
||||||
|
if selected_scenarios:
|
||||||
|
set_scenarios(current_user, current_edge, selected_scenarios)
|
||||||
|
return redirect(current_edge.url)
|
||||||
|
|
||||||
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return HttpResponseNotAllowed(['GET', 'POST'])
|
return HttpResponseNotAllowed(['GET', 'POST'])
|
||||||
|
|
||||||
@ -1525,6 +1693,12 @@ def package_scenarios(request, package_uuid):
|
|||||||
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
|
current_package = PackageManager.get_package_by_id(current_user, package_uuid)
|
||||||
|
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
|
|
||||||
|
if 'application/json' in request.META.get('HTTP_ACCEPT'): #request.headers.get('Accept') == 'application/json':
|
||||||
|
scens = Scenario.objects.filter(package=current_package).order_by('name')
|
||||||
|
res = [{'name': s.name, 'url': s.url, 'uuid': s.uuid} for s in scens]
|
||||||
|
return JsonResponse(res, safe=False)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = f'enviPath - {current_package.name} - Scenarios'
|
context['title'] = f'enviPath - {current_package.name} - Scenarios'
|
||||||
|
|
||||||
@ -1587,7 +1761,6 @@ def users(request):
|
|||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = f'enviPath - Users'
|
context['title'] = f'enviPath - Users'
|
||||||
|
|
||||||
context['meta']['current_package'] = context['meta']['user'].default_package
|
|
||||||
context['object_type'] = 'user'
|
context['object_type'] = 'user'
|
||||||
context['breadcrumbs'] = [
|
context['breadcrumbs'] = [
|
||||||
{'Home': s.SERVER_URL},
|
{'Home': s.SERVER_URL},
|
||||||
@ -1611,27 +1784,27 @@ def user(request, user_uuid):
|
|||||||
if str(current_user.uuid) != user_uuid and not current_user.is_superuser:
|
if str(current_user.uuid) != user_uuid and not current_user.is_superuser:
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
user = UserManager.get_user_by_id(current_user, user_uuid)
|
requested_user = UserManager.get_user_by_id(current_user, user_uuid)
|
||||||
|
|
||||||
context = get_base_context(request)
|
context = get_base_context(request, for_user=requested_user)
|
||||||
context['title'] = f'enviPath - User'
|
context['title'] = f'enviPath - User'
|
||||||
|
|
||||||
context['object_type'] = 'user'
|
context['object_type'] = 'user'
|
||||||
context['breadcrumbs'] = [
|
context['breadcrumbs'] = [
|
||||||
{'Home': s.SERVER_URL},
|
{'Home': s.SERVER_URL},
|
||||||
{'User': s.SERVER_URL + '/user'},
|
{'User': s.SERVER_URL + '/user'},
|
||||||
{current_user.username: current_user.url}
|
{current_user.username: requested_user.url}
|
||||||
]
|
]
|
||||||
|
|
||||||
context['user'] = user
|
context['user'] = requested_user
|
||||||
|
|
||||||
model_qs = EPModel.objects.none()
|
model_qs = EPModel.objects.none()
|
||||||
for p in PackageManager.get_all_readable_packages(current_user, include_reviewed=True):
|
for p in PackageManager.get_all_readable_packages(requested_user, include_reviewed=True):
|
||||||
model_qs |= p.models
|
model_qs |= p.models
|
||||||
|
|
||||||
context['models'] = model_qs
|
context['models'] = model_qs
|
||||||
|
|
||||||
context['tokens'] = APIToken.objects.filter(user=current_user)
|
context['tokens'] = APIToken.objects.filter(user=requested_user)
|
||||||
|
|
||||||
return render(request, 'objects/user.html', context)
|
return render(request, 'objects/user.html', context)
|
||||||
|
|
||||||
@ -1700,8 +1873,6 @@ def user(request, user_uuid):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print(setting)
|
|
||||||
|
|
||||||
return HttpResponseBadRequest()
|
return HttpResponseBadRequest()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -1715,7 +1886,6 @@ def groups(request):
|
|||||||
context = get_base_context(request)
|
context = get_base_context(request)
|
||||||
context['title'] = f'enviPath - Groups'
|
context['title'] = f'enviPath - Groups'
|
||||||
|
|
||||||
context['meta']['current_package'] = context['meta']['user'].default_package
|
|
||||||
context['object_type'] = 'group'
|
context['object_type'] = 'group'
|
||||||
context['breadcrumbs'] = [
|
context['breadcrumbs'] = [
|
||||||
{'Home': s.SERVER_URL},
|
{'Home': s.SERVER_URL},
|
||||||
@ -1764,12 +1934,10 @@ def group(request, group_uuid):
|
|||||||
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
|
|
||||||
if s.DEBUG:
|
log_post_params(request)
|
||||||
for k, v in request.POST.items():
|
|
||||||
print(k, v)
|
|
||||||
|
|
||||||
if hidden := request.POST.get('hidden', None):
|
if hidden := request.POST.get('hidden', None):
|
||||||
if hidden == 'delete-group':
|
if hidden == 'delete':
|
||||||
current_group.delete()
|
current_group.delete()
|
||||||
return redirect(s.SERVER_URL + '/group')
|
return redirect(s.SERVER_URL + '/group')
|
||||||
else:
|
else:
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -38,10 +38,8 @@ def migration(request):
|
|||||||
res = True
|
res = True
|
||||||
|
|
||||||
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
||||||
# if comp['smiles'] != 'CC1=C(C(=C(C=N1)CO)C=O)O':
|
|
||||||
# continue
|
|
||||||
|
|
||||||
products = FormatConverter.apply(comp['smiles'], smirks, preprocess_smiles=True, bracketize=False)
|
products = FormatConverter.apply(comp['smiles'], smirks)
|
||||||
|
|
||||||
all_rdkit_prods = []
|
all_rdkit_prods = []
|
||||||
for ps in products:
|
for ps in products:
|
||||||
@ -130,7 +128,7 @@ def migration_detail(request, package_uuid, rule_uuid):
|
|||||||
# if comp['smiles'] != 'CC1=C(C(=C(C=N1)CO)C=O)O':
|
# if comp['smiles'] != 'CC1=C(C(=C(C=N1)CO)C=O)O':
|
||||||
# continue
|
# continue
|
||||||
|
|
||||||
products = FormatConverter.apply(comp['smiles'], smirks, preprocess_smiles=True, bracketize=False)
|
products = FormatConverter.apply(comp['smiles'], smirks)
|
||||||
|
|
||||||
all_rdkit_prods = []
|
all_rdkit_prods = []
|
||||||
for ps in products:
|
for ps in products:
|
||||||
|
|||||||
147
static/js/pps.js
147
static/js/pps.js
@ -638,3 +638,150 @@ function fillPRCurve(modelUri, onclick){
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function handleAssessmentResponse(depict_url, data) {
|
||||||
|
var inside_app_domain = "<a class='list-group-item'>This compound is " + (data["assessment"]["inside_app_domain"] ? "inside" : "outside") + " the Applicability Domain derived from the chemical (PCA) space constructed using the training data." + "</a>";
|
||||||
|
var functionalGroupsImgSrc = null;
|
||||||
|
var reactivityCentersImgSrc = null;
|
||||||
|
|
||||||
|
if (data['assessment']['node'] !== undefined) {
|
||||||
|
functionalGroupsImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>";
|
||||||
|
reactivityCentersImgSrc = "<img width='400' src='" + data['assessment']['node']['image'] + "'>"
|
||||||
|
} else {
|
||||||
|
functionalGroupsImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">";
|
||||||
|
reactivityCentersImgSrc = "<img width='400' src=\"" + depict_url + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "\">"
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl = `<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="app-domain-assessment-functional-groups-link" data-toggle="collapse" data-parent="#app-domain-assessment" href="#app-domain-assessment-functional-groups">Functional Groups Covered by Model</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="app-domain-assessment-functional-groups" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
${inside_app_domain}
|
||||||
|
<p></p>
|
||||||
|
<div id="image-div" align="center">
|
||||||
|
${functionalGroupsImgSrc}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="app-domain-assessment-reactivity-centers-link" data-toggle="collapse" data-parent="#app-domain-assessment" href="#app-domain-assessment-reactivity-centers">Reactivity Centers</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="app-domain-assessment-reactivity-centers" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
<div id="image-div" align="center">
|
||||||
|
${reactivityCentersImgSrc}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`
|
||||||
|
|
||||||
|
var transformations = '';
|
||||||
|
|
||||||
|
for (t in data['assessment']['transformations']) {
|
||||||
|
transObj = data['assessment']['transformations'][t];
|
||||||
|
var neighbors = '';
|
||||||
|
for (n in transObj['neighbors']) {
|
||||||
|
neighObj = transObj['neighbors'][n];
|
||||||
|
var neighImg = "<img width='100%' src='" + transObj['rule']['url'] + "?smiles=" + encodeURIComponent(neighObj['smiles']) + "'>";
|
||||||
|
var objLink = `<a class='list-group-item' href="${neighObj['url']}">${neighObj['name']}</a>`
|
||||||
|
var neighPredProb = "<a class='list-group-item'>Predicted probability: " + neighObj['probability'].toFixed(2) + "</a>";
|
||||||
|
|
||||||
|
var pwLinks = '';
|
||||||
|
for (pw in neighObj['related_pathways']) {
|
||||||
|
var pwObj = neighObj['related_pathways'][pw];
|
||||||
|
pwLinks += "<a class='list-group-item' href=" + pwObj['url'] + ">" + pwObj['name'] + "</a>";
|
||||||
|
}
|
||||||
|
|
||||||
|
var expPathways = `
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="transformation-${t}-neighbor-${n}-exp-pathway-link" data-toggle="collapse" data-parent="#transformation-${t}-neighbor-${n}" href="#transformation-${t}-neighbor-${n}-exp-pathway">Experimental Pathways</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="transformation-${t}-neighbor-${n}-exp-pathway" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
${pwLinks}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
|
||||||
|
if (pwLinks === '') {
|
||||||
|
expPathways = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
neighbors += `
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="transformation-${t}-neighbor-${n}-link" data-toggle="collapse" data-parent="#transformation-${t}" href="#transformation-${t}-neighbor-${n}">Analog Transformation on ${neighObj['name']}</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="transformation-${t}-neighbor-${n}" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
${objLink}
|
||||||
|
${neighPredProb}
|
||||||
|
${expPathways}
|
||||||
|
<p></p>
|
||||||
|
<div id="image-div" align="center">
|
||||||
|
${neighImg}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
var panelName = null;
|
||||||
|
var objLink = null;
|
||||||
|
if (transObj['is_predicted']) {
|
||||||
|
panelName = `Predicted Transformation by ${transObj['rule']['name']}`;
|
||||||
|
for (e in transObj['edges']) {
|
||||||
|
objLink = `<a class='list-group-item' href="${transObj['edges'][e]['url']}">${transObj['edges'][e]['name']}</a>`
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panelName = `Potential Transformation by applying ${transObj['rule']['name']}`;
|
||||||
|
objLink = `<a class='list-group-item' href="${transObj['rule']['url']}">${transObj['rule']['name']}</a>`
|
||||||
|
}
|
||||||
|
|
||||||
|
var predProb = "<a class='list-group-item'>Predicted probability: " + transObj['probability'].toFixed(2) + "</a>";
|
||||||
|
var timesTriggered = "<a class='list-group-item'>This rule has triggered " + transObj['times_triggered'] + " times in the training set</a>";
|
||||||
|
var reliability = "<a class='list-group-item'>Reliability: " + transObj['reliability'].toFixed(2) + " (" + (transObj['reliability'] > data['ad_params']['reliability_threshold'] ? ">" : "<") + " Reliability Threshold of " + data['ad_params']['reliability_threshold'] + ") </a>";
|
||||||
|
var localCompatibility = "<a class='list-group-item'>Local Compatibility: " + transObj['local_compatibility'].toFixed(2) + " (" + (transObj['local_compatibility'] > data['ad_params']['local_compatibilty_threshold'] ? ">" : "<") + " Local Compatibility Threshold of " + data['ad_params']['local_compatibilty_threshold'] + ")</a>";
|
||||||
|
|
||||||
|
var transImg = "<img width='100%' src='" + transObj['rule']['url'] + "?smiles=" + encodeURIComponent(data['assessment']['smiles']) + "'>";
|
||||||
|
|
||||||
|
var transformation = `
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="transformation-${t}-link" data-toggle="collapse" data-parent="#transformation-${t}" href="#transformation-${t}">${panelName}</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="transformation-${t}" class="panel-collapse collapse">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
${objLink}
|
||||||
|
${predProb}
|
||||||
|
${timesTriggered}
|
||||||
|
${reliability}
|
||||||
|
${localCompatibility}
|
||||||
|
<p></p>
|
||||||
|
<div id="image-div" align="center">
|
||||||
|
${transImg}
|
||||||
|
</div>
|
||||||
|
<p></p>
|
||||||
|
${neighbors}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
transformations += transformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = tpl + transformations;
|
||||||
|
|
||||||
|
$("#appDomainAssessmentResultTable").append(res);
|
||||||
|
|
||||||
|
}
|
||||||
208
static/js/pw.js
208
static/js/pw.js
@ -1,5 +1,4 @@
|
|||||||
console.log("loaded")
|
console.log("loaded pw.js")
|
||||||
|
|
||||||
|
|
||||||
function predictFromNode(url) {
|
function predictFromNode(url) {
|
||||||
$.post("", {node: url})
|
$.post("", {node: url})
|
||||||
@ -28,61 +27,164 @@ function draw(pathway, elem) {
|
|||||||
const horizontalSpacing = 75; // horizontal space between nodes
|
const horizontalSpacing = 75; // horizontal space between nodes
|
||||||
const depthMap = new Map();
|
const depthMap = new Map();
|
||||||
|
|
||||||
nodes.forEach(node => {
|
// Sort nodes by depth first to minimize crossings
|
||||||
|
const sortedNodes = [...nodes].sort((a, b) => a.depth - b.depth);
|
||||||
|
|
||||||
|
sortedNodes.forEach(node => {
|
||||||
if (!depthMap.has(node.depth)) {
|
if (!depthMap.has(node.depth)) {
|
||||||
depthMap.set(node.depth, 0);
|
depthMap.set(node.depth, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nodesInLevel = nodes.filter(n => n.depth === node.depth).length;
|
const nodesInLevel = nodes.filter(n => n.depth === node.depth).length;
|
||||||
node.fx = width / 2 + depthMap.get(node.depth) * horizontalSpacing - ((nodesInLevel - 1) * horizontalSpacing) / 2;
|
|
||||||
node.fy = node.depth * levelSpacing + 50;
|
|
||||||
|
|
||||||
|
// For pseudo nodes, try to position them to minimize crossings
|
||||||
|
if (node.pseudo) {
|
||||||
|
const parentLinks = links.filter(l => l.target.id === node.id);
|
||||||
|
const childLinks = links.filter(l => l.source.id === node.id);
|
||||||
|
|
||||||
|
if (parentLinks.length > 0 && childLinks.length > 0) {
|
||||||
|
const parentX = parentLinks[0].source.x || (width / 2);
|
||||||
|
const childrenX = childLinks.map(l => l.target.x || (width / 2));
|
||||||
|
const avgChildX = childrenX.reduce((sum, x) => sum + x, 0) / childrenX.length;
|
||||||
|
|
||||||
|
// Position pseudo node between parent and average child position
|
||||||
|
node.fx = (parentX + avgChildX) / 2;
|
||||||
|
} else {
|
||||||
|
node.fx = width / 2 + depthMap.get(node.depth) * horizontalSpacing - ((nodesInLevel - 1) * horizontalSpacing) / 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.fx = width / 2 + depthMap.get(node.depth) * horizontalSpacing - ((nodesInLevel - 1) * horizontalSpacing) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.fy = node.depth * levelSpacing + 50;
|
||||||
depthMap.set(node.depth, depthMap.get(node.depth) + 1);
|
depthMap.set(node.depth, depthMap.get(node.depth) + 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Funktion für das Update der Positionen
|
// Function to update pseudo node positions based on connected nodes
|
||||||
|
function updatePseudoNodePositions() {
|
||||||
|
nodes.forEach(node => {
|
||||||
|
if (node.pseudo && !node.isDragging) { // Don't auto-update if being dragged
|
||||||
|
const parentLinks = links.filter(l => l.target.id === node.id);
|
||||||
|
const childLinks = links.filter(l => l.source.id === node.id);
|
||||||
|
|
||||||
|
if (parentLinks.length > 0 && childLinks.length > 0) {
|
||||||
|
const parent = parentLinks[0].source;
|
||||||
|
const children = childLinks.map(l => l.target);
|
||||||
|
|
||||||
|
// Calculate optimal position to minimize crossing
|
||||||
|
const parentX = parent.x;
|
||||||
|
const parentY = parent.y;
|
||||||
|
const childrenX = children.map(c => c.x);
|
||||||
|
const childrenY = children.map(c => c.y);
|
||||||
|
const avgChildX = d3.mean(childrenX);
|
||||||
|
const avgChildY = d3.mean(childrenY);
|
||||||
|
|
||||||
|
// Position pseudo node between parent and average child position
|
||||||
|
node.fx = (parentX + avgChildX) / 2;
|
||||||
|
node.fy = (parentY + avgChildY) / 2; // Allow vertical movement too
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Enhanced ticked function
|
||||||
function ticked() {
|
function ticked() {
|
||||||
|
// Update pseudo node positions first
|
||||||
|
updatePseudoNodePositions();
|
||||||
|
|
||||||
link.attr("x1", d => d.source.x)
|
link.attr("x1", d => d.source.x)
|
||||||
.attr("y1", d => d.source.y)
|
.attr("y1", d => d.source.y)
|
||||||
.attr("x2", d => d.target.x)
|
.attr("x2", d => d.target.x)
|
||||||
.attr("y2", d => d.target.y);
|
.attr("y2", d => d.target.y);
|
||||||
|
|
||||||
node.attr("transform", d => `translate(${d.x},${d.y})`);
|
node.attr("transform", d => `translate(${d.x},${d.y})`);
|
||||||
|
|
||||||
nodes.forEach(n => {
|
|
||||||
if (n.pseudo) {
|
|
||||||
// Alle Kinder dieses Pseudonodes finden
|
|
||||||
const childLinks = links.filter(l => l.source.id === n.id);
|
|
||||||
const childNodes = childLinks.map(l => l.target);
|
|
||||||
if (childNodes.length > 0) {
|
|
||||||
// Durchschnitt der Kinderpositionen berechnen
|
|
||||||
const avgX = d3.mean(childNodes, d => d.x);
|
|
||||||
const avgY = d3.mean(childNodes, d => d.y);
|
|
||||||
n.fx = avgX;
|
|
||||||
// keep level as is
|
|
||||||
n.fy = n.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
//simulation.alpha(0.3).restart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dragstarted(event, d) {
|
function dragstarted(event, d) {
|
||||||
if (!event.active) simulation.alphaTarget(0.3).restart();
|
if (!event.active) simulation.alphaTarget(0.3).restart();
|
||||||
d.fx = d.x; // Setzt die Fixierung auf die aktuelle Position
|
d.fx = d.x;
|
||||||
d.fy = d.y;
|
d.fy = d.y;
|
||||||
|
|
||||||
|
// Mark if this node is being dragged
|
||||||
|
d.isDragging = true;
|
||||||
|
|
||||||
|
// If dragging a non-pseudo node, mark connected pseudo nodes for update
|
||||||
|
if (!d.pseudo) {
|
||||||
|
markConnectedPseudoNodes(d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dragged(event, d) {
|
function dragged(event, d) {
|
||||||
d.fx = event.x; // Position direkt an Maus anpassen
|
d.fx = event.x;
|
||||||
d.fy = event.y;
|
d.fy = event.y;
|
||||||
|
|
||||||
|
// Update connected pseudo nodes in real-time
|
||||||
|
if (!d.pseudo) {
|
||||||
|
updateConnectedPseudoNodes(d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dragended(event, d) {
|
function dragended(event, d) {
|
||||||
if (!event.active) simulation.alphaTarget(0);
|
if (!event.active) simulation.alphaTarget(0);
|
||||||
// Knoten bleibt an der neuen Position und wird nicht zurückgezogen
|
|
||||||
|
// Mark that dragging has ended
|
||||||
|
d.isDragging = false;
|
||||||
|
|
||||||
|
// Final update of connected pseudo nodes
|
||||||
|
if (!d.pseudo) {
|
||||||
|
updateConnectedPseudoNodes(d);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to mark connected pseudo nodes
|
||||||
|
function markConnectedPseudoNodes(draggedNode) {
|
||||||
|
// Find pseudo nodes connected to this node
|
||||||
|
const connectedPseudos = new Set();
|
||||||
|
|
||||||
|
// Check as parent of pseudo nodes
|
||||||
|
links.filter(l => l.source.id === draggedNode.id && l.target.pseudo)
|
||||||
|
.forEach(l => connectedPseudos.add(l.target));
|
||||||
|
|
||||||
|
// Check as child of pseudo nodes
|
||||||
|
links.filter(l => l.target.id === draggedNode.id && l.source.pseudo)
|
||||||
|
.forEach(l => connectedPseudos.add(l.source));
|
||||||
|
|
||||||
|
return connectedPseudos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to update connected pseudo nodes
|
||||||
|
function updateConnectedPseudoNodes(draggedNode) {
|
||||||
|
const connectedPseudos = markConnectedPseudoNodes(draggedNode);
|
||||||
|
|
||||||
|
connectedPseudos.forEach(pseudoNode => {
|
||||||
|
if (!pseudoNode.isDragging) { // Don't update if pseudo node is being dragged
|
||||||
|
const parentLinks = links.filter(l => l.target.id === pseudoNode.id);
|
||||||
|
const childLinks = links.filter(l => l.source.id === pseudoNode.id);
|
||||||
|
|
||||||
|
if (parentLinks.length > 0 && childLinks.length > 0) {
|
||||||
|
const parent = parentLinks[0].source;
|
||||||
|
const children = childLinks.map(l => l.target);
|
||||||
|
|
||||||
|
const parentX = parent.fx || parent.x;
|
||||||
|
const parentY = parent.fy || parent.y;
|
||||||
|
const childrenX = children.map(c => c.fx || c.x);
|
||||||
|
const childrenY = children.map(c => c.fy || c.y);
|
||||||
|
const avgChildX = d3.mean(childrenX);
|
||||||
|
const avgChildY = d3.mean(childrenY);
|
||||||
|
|
||||||
|
// Update pseudo node position - allow both X and Y movement
|
||||||
|
pseudoNode.fx = (parentX + avgChildX) / 2;
|
||||||
|
pseudoNode.fy = (parentY + avgChildY) / 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Restart simulation with lower alpha to smooth the transition
|
||||||
|
simulation.alpha(0.1).restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// t -> ref to "this" from d3
|
// t -> ref to "this" from d3
|
||||||
function nodeClick(event, node, t) {
|
function nodeClick(event, node, t) {
|
||||||
@ -140,10 +242,19 @@ function draw(pathway, elem) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function node_popup(n) {
|
function node_popup(n) {
|
||||||
popupContent = "<a href='" + n.url + "'>" + n.name + "</a><br>";
|
popupContent = "<a href='" + n.url + "'>" + n.name + "</a><br>";
|
||||||
popupContent += "Depth " + n.depth + "<br>"
|
popupContent += "Depth " + n.depth + "<br>"
|
||||||
|
|
||||||
|
if (appDomainViewEnabled) {
|
||||||
|
if (n.app_domain != null) {
|
||||||
|
popupContent += "This compound is " + (n.app_domain['inside_app_domain'] ? "inside" : "outside") + " the Applicability Domain derived from the chemical (PCA) space constructed using the training data." + "<br>"
|
||||||
|
if (n.app_domain['uncovered_functional_groups']) {
|
||||||
|
popupContent += "Compound contains functional groups not covered by the training set <br>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
popupContent += "<img src='" + n.image + "' width='" + 20 * nodeRadius + "'><br>"
|
popupContent += "<img src='" + n.image + "' width='" + 20 * nodeRadius + "'><br>"
|
||||||
if (n.scenarios.length > 0) {
|
if (n.scenarios.length > 0) {
|
||||||
popupContent += '<b>Half-lives and related scenarios:</b><br>'
|
popupContent += '<b>Half-lives and related scenarios:</b><br>'
|
||||||
@ -162,12 +273,23 @@ function draw(pathway, elem) {
|
|||||||
|
|
||||||
function edge_popup(e) {
|
function edge_popup(e) {
|
||||||
popupContent = "<a href='" + e.url + "'>" + e.name + "</a><br>";
|
popupContent = "<a href='" + e.url + "'>" + e.name + "</a><br>";
|
||||||
|
|
||||||
|
if (e.app_domain) {
|
||||||
|
adcontent = "<p>";
|
||||||
|
if (e.app_domain["times_triggered"]) {
|
||||||
|
adcontent += "This rule triggered " + e.app_domain["times_triggered"] + " times in the training set<br>";
|
||||||
|
}
|
||||||
|
adcontent += "Reliability " + e.app_domain["reliability"].toFixed(2) + " (" + (e.app_domain["reliability"] > e.app_domain["reliability_threshold"] ? ">" : "<") + " Reliability Threshold of " + e.app_domain["reliability_threshold"] + ")<br>";
|
||||||
|
adcontent += "Local Compatibility " + e.app_domain["local_compatibility"].toFixed(2) + " (" + (e.app_domain["local_compatibility"] > e.app_domain["local_compatibility_threshold"] ? ">" : "<") + " Local Compatibility Threshold of " + e.app_domain["local_compatibility_threshold"] + ")<br>";
|
||||||
|
adcontent += "</p>";
|
||||||
|
popupContent += adcontent;
|
||||||
|
}
|
||||||
|
|
||||||
popupContent += "<img src='" + e.image + "' width='" + 20 * nodeRadius + "'><br>"
|
popupContent += "<img src='" + e.image + "' width='" + 20 * nodeRadius + "'><br>"
|
||||||
if (e.reaction_probability) {
|
if (e.reaction_probability) {
|
||||||
popupContent += '<b>Probability:</b><br>' + e.reaction_probability.toFixed(3) + '<br>';
|
popupContent += '<b>Probability:</b><br>' + e.reaction_probability.toFixed(3) + '<br>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (e.scenarios.length > 0) {
|
if (e.scenarios.length > 0) {
|
||||||
popupContent += '<b>Half-lives and related scenarios:</b><br>'
|
popupContent += '<b>Half-lives and related scenarios:</b><br>'
|
||||||
for (var s of e.scenarios) {
|
for (var s of e.scenarios) {
|
||||||
@ -233,13 +355,12 @@ function draw(pathway, elem) {
|
|||||||
.enter().append("line")
|
.enter().append("line")
|
||||||
// Check if target is pseudo and draw marker only if not pseudo
|
// Check if target is pseudo and draw marker only if not pseudo
|
||||||
.attr("class", d => d.target.pseudo ? "link_no_arrow" : "link")
|
.attr("class", d => d.target.pseudo ? "link_no_arrow" : "link")
|
||||||
// .on("mouseover", (event, d) => {
|
.attr("marker-end", d => d.target.pseudo ? '' : 'url(#arrow)')
|
||||||
// tooltip.style("visibility", "visible")
|
|
||||||
// .text(`Link: ${d.source.id} → ${d.target.id}`)
|
// add element to links array
|
||||||
// .style("top", `${event.pageY + 5}px`)
|
link.each(function (d) {
|
||||||
// .style("left", `${event.pageX + 5}px`);
|
d.el = this; // attach the DOM element to the data object
|
||||||
// })
|
});
|
||||||
// .on("mouseout", () => tooltip.style("visibility", "hidden"));
|
|
||||||
|
|
||||||
pop_add(link, "Reaction", edge_popup);
|
pop_add(link, "Reaction", edge_popup);
|
||||||
|
|
||||||
@ -255,20 +376,10 @@ function draw(pathway, elem) {
|
|||||||
.on("click", function (event, d) {
|
.on("click", function (event, d) {
|
||||||
d3.select(this).select("circle").classed("highlighted", !d3.select(this).select("circle").classed("highlighted"));
|
d3.select(this).select("circle").classed("highlighted", !d3.select(this).select("circle").classed("highlighted"));
|
||||||
})
|
})
|
||||||
// .on("mouseover", (event, d) => {
|
|
||||||
// if (d.pseudo) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// tooltip.style("visibility", "visible")
|
|
||||||
// .text(`Node: ${d.id} Depth: ${d.depth}`)
|
|
||||||
// .style("top", `${event.pageY + 5}px`)
|
|
||||||
// .style("left", `${event.pageX + 5}px`);
|
|
||||||
// })
|
|
||||||
// .on("mouseout", () => tooltip.style("visibility", "hidden"));
|
|
||||||
|
|
||||||
// Kreise für die Knoten hinzufügen
|
// Kreise für die Knoten hinzufügen
|
||||||
node.append("circle")
|
node.append("circle")
|
||||||
// make radius "invisible"
|
// make radius "invisible" for pseudo nodes
|
||||||
.attr("r", d => d.pseudo ? 0.01 : nodeRadius)
|
.attr("r", d => d.pseudo ? 0.01 : nodeRadius)
|
||||||
.style("fill", "#e8e8e8");
|
.style("fill", "#e8e8e8");
|
||||||
|
|
||||||
@ -280,5 +391,10 @@ function draw(pathway, elem) {
|
|||||||
.attr("width", nodeRadius * 2)
|
.attr("width", nodeRadius * 2)
|
||||||
.attr("height", nodeRadius * 2);
|
.attr("height", nodeRadius * 2);
|
||||||
|
|
||||||
|
// add element to nodes array
|
||||||
|
node.each(function (d) {
|
||||||
|
d.el = this; // attach the DOM element to the data object
|
||||||
|
});
|
||||||
|
|
||||||
pop_add(node, "Compound", node_popup);
|
pop_add(node, "Compound", node_popup);
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
{% if meta.can_edit %}
|
{% if meta.can_edit and meta.enabled_features.MODEL_BUILDING %}
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#new_model_modal">
|
<a role="button" data-toggle="modal" data-target="#new_model_modal">
|
||||||
<span class="glyphicon glyphicon-plus"></span> New Model</a>
|
<span class="glyphicon glyphicon-plus"></span> New Model</a>
|
||||||
|
|||||||
@ -8,7 +8,11 @@
|
|||||||
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
|
<i class="glyphicon glyphicon-plus"></i> Add Structure</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_compound_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Compound</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -4,7 +4,11 @@
|
|||||||
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Compound Structure</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_compound_structure_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Compound Structure</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
10
templates/actions/objects/edge.html
Normal file
10
templates/actions/objects/edge.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% if meta.can_edit %}
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i> Delete Edge</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
@ -1,10 +1,10 @@
|
|||||||
{% if meta.can_edit %}
|
{% if meta.can_edit %}
|
||||||
<li>
|
|
||||||
<a role="button" data-toggle="modal" data-target="#delete_group_modal">
|
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Group</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#edit_group_member_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_group_member_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Add/Remove Member</a>
|
<i class="glyphicon glyphicon-trash"></i> Add/Remove Member</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i> Delete Group</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
{% if meta.can_edit %}
|
{% if meta.can_edit %}
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_model_modal">
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Model</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Model</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -4,7 +4,11 @@
|
|||||||
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Node</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_node_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Node</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Node</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@ -7,12 +7,16 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_package_permissions_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_package_permissions_modal">
|
||||||
<i class="glyphicon glyphicon-user"></i> Edit Permissions</a>
|
<i class="glyphicon glyphicon-user"></i> Edit Permissions</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#publish_package_modal">
|
||||||
|
<i class="glyphicon glyphicon-bullhorn"></i> Publish Package</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#set_license_modal">
|
<a role="button" data-toggle="modal" data-target="#set_license_modal">
|
||||||
<i class="glyphicon glyphicon-duplicate"></i> License</a>
|
<i class="glyphicon glyphicon-duplicate"></i> License</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_package_modal">
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Package</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Package</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -8,9 +8,18 @@
|
|||||||
<i class="glyphicon glyphicon-plus"></i> Add Reaction</a>
|
<i class="glyphicon glyphicon-plus"></i> Add Reaction</a>
|
||||||
</li>
|
</li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#download_pathway_modal">
|
||||||
|
<i class="glyphicon glyphicon-floppy-save"></i> Download Pathway</a>
|
||||||
|
</li>
|
||||||
|
<li role="separator" class="divider"></li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#edit_pathway_modal">
|
<a class="button" data-toggle="modal" data-target="#edit_pathway_modal">
|
||||||
<i class="glyphicon glyphicon-plus"></i> Edit Pathway</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Pathway</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
</li>
|
</li>
|
||||||
{# <li>#}
|
{# <li>#}
|
||||||
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
{# <a class="button" data-toggle="modal" data-target="#add_pathway_edge_modal">#}
|
||||||
@ -26,7 +35,7 @@
|
|||||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_pathway_modal">
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Pathway</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Pathway</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -4,7 +4,11 @@
|
|||||||
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Reaction</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#delete_reaction_modal">
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Reaction</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -3,4 +3,12 @@
|
|||||||
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
<a role="button" data-toggle="modal" data-target="#edit_rule_modal">
|
||||||
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
|
<i class="glyphicon glyphicon-edit"></i> Edit Rule</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a role="button" data-toggle="modal" data-target="#set_scenario_modal">
|
||||||
|
<i class="glyphicon glyphicon-plus"></i> Set Scenarios</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i> Delete Rule</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -16,7 +16,7 @@
|
|||||||
{# <i class="glyphicon glyphicon-console"></i> Manage API Token</a>#}
|
{# <i class="glyphicon glyphicon-console"></i> Manage API Token</a>#}
|
||||||
{# </li>#}
|
{# </li>#}
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" data-target="#delete_user_modal">
|
<a role="button" data-toggle="modal" data-target="#generic_delete_modal">
|
||||||
<i class="glyphicon glyphicon-trash"></i> Delete Account</a>
|
<i class="glyphicon glyphicon-trash"></i> Delete Account</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -51,7 +51,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var u = "//matomo.envipath.com/";
|
var u = "//matomo.envipath.com/";
|
||||||
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
_paq.push(['setTrackerUrl', u + 'matomo.php']);
|
||||||
_paq.push(['setSiteId', '7']);
|
_paq.push(['setSiteId', '10']);
|
||||||
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
|
||||||
g.async = true;
|
g.async = true;
|
||||||
g.src = u + 'matomo.js';
|
g.src = u + 'matomo.js';
|
||||||
@ -83,21 +83,26 @@
|
|||||||
<!-- Collect the nav links, forms, and other content for toggling -->
|
<!-- Collect the nav links, forms, and other content for toggling -->
|
||||||
<div class="collapse navbar-collapse collapse-framework navbar-collapse-framework" id="navbarCollapse">
|
<div class="collapse navbar-collapse collapse-framework navbar-collapse-framework" id="navbarCollapse">
|
||||||
<ul class="nav navbar-nav navbar-nav-framework">
|
<ul class="nav navbar-nav navbar-nav-framework">
|
||||||
<li class="dropdown">
|
|
||||||
<a data-toggle="dropdown" class="dropdown-toggle" href="#">Predict Pathway<b class="caret"></b></a>
|
|
||||||
<ul role="menu" class="dropdown-menu">
|
|
||||||
<li>
|
<li>
|
||||||
<a class="button" data-toggle="modal" data-target="#predict_modal">
|
<a class="button" data-toggle="modal" data-target="#predict_modal">
|
||||||
<i class=" glyphicon glyphicon-tag"></i> Predict Pathway
|
Predict Pathway
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
{# <li class="dropdown">#}
|
||||||
<a class="button" data-toggle="modal" data-target="#batch_predict_modal">
|
{# <a data-toggle="dropdown" class="dropdown-toggle" href="#">Predict Pathway<b class="caret"></b></a>#}
|
||||||
<i class=" glyphicon glyphicon-tags"></i> Batch Prediction
|
{# <ul role="menu" class="dropdown-menu">#}
|
||||||
</a>
|
{# <li>#}
|
||||||
</li>
|
{# <a class="button" data-toggle="modal" data-target="#predict_modal">#}
|
||||||
</ul>
|
{# <i class=" glyphicon glyphicon-tag"></i> Predict Pathway#}
|
||||||
</li>
|
{# </a>#}
|
||||||
|
{# </li>#}
|
||||||
|
{# <li>#}
|
||||||
|
{# <a class="button" data-toggle="modal" data-target="#batch_predict_modal">#}
|
||||||
|
{# <i class=" glyphicon glyphicon-tags"></i> Batch Prediction#}
|
||||||
|
{# </a>#}
|
||||||
|
{# </li>#}
|
||||||
|
{# </ul>#}
|
||||||
|
{# </li>#}
|
||||||
<li><a href="{{ meta.server_url }}/package" id="packageLink">Package</a></li>
|
<li><a href="{{ meta.server_url }}/package" id="packageLink">Package</a></li>
|
||||||
<li><a href="{{ meta.server_url }}/search" id="searchLink">Search</a></li>
|
<li><a href="{{ meta.server_url }}/search" id="searchLink">Search</a></li>
|
||||||
<li><a href="{{ meta.server_url }}/model" id="modelLink">Modelling</a></li>
|
<li><a href="{{ meta.server_url }}/model" id="modelLink">Modelling</a></li>
|
||||||
@ -192,6 +197,23 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
{% if meta.current_package.license %}
|
||||||
|
<p></p>
|
||||||
|
<div class="panel-group" id="license_accordion">
|
||||||
|
<div class="panel panel-default list-group-item" style="background-color:#f5f5f5">
|
||||||
|
<div class="panel-title">
|
||||||
|
<a data-toggle="collapse" data-parent="#licence_accordion" href="#license">License</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="license" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
<a target="_blank" href="{{ meta.current_package.license.link }}">
|
||||||
|
<img src="{{ meta.current_package.license.image_link }}">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- FOOTER -->
|
<!-- FOOTER -->
|
||||||
|
|||||||
@ -143,6 +143,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
|
$('#index-form').on("keydown", function (e) {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
goButtonClicked();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Code that should be executed once DOM is ready goes here
|
// Code that should be executed once DOM is ready goes here
|
||||||
$('#dropdown-predict').on('click', actionDropdownClicked);
|
$('#dropdown-predict').on('click', actionDropdownClicked);
|
||||||
$('#dropdown-search').on('click', actionDropdownClicked);
|
$('#dropdown-search').on('click', actionDropdownClicked);
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
.center-button {
|
.center-button {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 70%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
.center-message {
|
.center-message {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 40%;
|
top: 35%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|||||||
@ -16,14 +16,14 @@
|
|||||||
<div class="jumbotron">Create a new Model to
|
<div class="jumbotron">Create a new Model to
|
||||||
limit the number of degradation products in the
|
limit the number of degradation products in the
|
||||||
prediction. You just need to set a name and the packages
|
prediction. You just need to set a name and the packages
|
||||||
you want the object to be based on. If you want to use the
|
you want the object to be based on. There are multiple types of models available.
|
||||||
default options suggested by us, simply click Submit,
|
For additional information have a look at our
|
||||||
otherwise click Advanced Options.
|
<a target="_blank" href="https://wiki.envipath.org/index.php/relative-reasoning" role="button">wiki >></a>
|
||||||
</div>
|
</div>
|
||||||
<label for="name">Name</label>
|
<label for="model-name">Name</label>
|
||||||
<input id="name" name="model-name" class="form-control" placeholder="Name"/>
|
<input id="model-name" name="model-name" class="form-control" placeholder="Name"/>
|
||||||
<label for="description">Description</label>
|
<label for="model-description">Description</label>
|
||||||
<input id="description" name="model-description" class="form-control"
|
<input id="model-description" name="model-description" class="form-control"
|
||||||
placeholder="Description"/>
|
placeholder="Description"/>
|
||||||
<label for="model-type">Model Type</label>
|
<label for="model-type">Model Type</label>
|
||||||
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
<select id="model-type" name="model-type" class="form-control" data-width='100%'>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<!-- ML Based Form-->
|
<!-- ML Based Form-->
|
||||||
<div id="ml-relative-reasoning-specific-form">
|
<div id="ml-relative-reasoning-specific-form">
|
||||||
<!-- Rule Packages -->
|
<!-- Rule Packages -->
|
||||||
<label>Rule Packages</label><br>
|
<label for="ml-relative-reasoning-rule-packages">Rule Packages</label>
|
||||||
<select id="ml-relative-reasoning-rule-packages" name="ml-relative-reasoning-rule-packages"
|
<select id="ml-relative-reasoning-rule-packages" name="ml-relative-reasoning-rule-packages"
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
@ -53,7 +53,7 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<!-- Data Packages -->
|
<!-- Data Packages -->
|
||||||
<label>Data Packages</label><br>
|
<label for="ml-relative-reasoning-data-packages" >Data Packages</label>
|
||||||
<select id="ml-relative-reasoning-data-packages" name="ml-relative-reasoning-data-packages"
|
<select id="ml-relative-reasoning-data-packages" name="ml-relative-reasoning-data-packages"
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
@ -77,22 +77,24 @@
|
|||||||
class="form-control">
|
class="form-control">
|
||||||
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
<option value="MACCS" selected>MACCS Fingerprinter</option>
|
||||||
</select>
|
</select>
|
||||||
{% if 'plugins' in meta.enabled_features %}
|
{% if meta.enabled_features.PLUGINS and additional_descriptors %}
|
||||||
<!-- Property Plugins go here -->
|
<!-- Property Plugins go here -->
|
||||||
<label for="ml-relative-reasoning-additional-fingerprinter">Fingerprinter</label>
|
<label for="ml-relative-reasoning-additional-fingerprinter">Additional Fingerprinter / Descriptors</label>
|
||||||
<select id="ml-relative-reasoning-additional-fingerprinter"
|
<select id="ml-relative-reasoning-additional-fingerprinter" name="ml-relative-reasoning-additional-fingerprinter" class="form-control">
|
||||||
name="ml-relative-reasoning-additional-fingerprinter"
|
<option disabled selected>Select Additional Fingerprinter / Descriptor</option>
|
||||||
class="form-control">
|
{% for k, v in additional_descriptors.items %}
|
||||||
|
<option value="{{ v }}">{{ k }}</option>
|
||||||
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<label for="ml-relative-reasoning-threshold">Threshold</label>
|
<label for="ml-relative-reasoning-threshold">Threshold</label>
|
||||||
<input type="number" min="0" , max="1" step="0.05" value="0.5"
|
<input type="number" min="0" max="1" step="0.05" value="0.5"
|
||||||
id="ml-relative-reasoning-threshold"
|
id="ml-relative-reasoning-threshold"
|
||||||
name="ml-relative-reasoning-threshold" class="form-control">
|
name="ml-relative-reasoning-threshold" class="form-control">
|
||||||
|
|
||||||
<!-- Evaluation -->
|
<!-- Evaluation -->
|
||||||
|
<label for="ml-relative-reasoning-evaluation-packages">Evaluation Packages</label>
|
||||||
<label>Evaluation Packages</label><br>
|
|
||||||
<select id="ml-relative-reasoning-evaluation-packages" name="ml-relative-reasoning-evaluation-packages"
|
<select id="ml-relative-reasoning-evaluation-packages" name="ml-relative-reasoning-evaluation-packages"
|
||||||
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
data-actions-box='true' class="form-control" multiple data-width='100%'>
|
||||||
<option disabled>Reviewed Packages</option>
|
<option disabled>Reviewed Packages</option>
|
||||||
@ -110,6 +112,26 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
{% if meta.enabled_features.APPLICABILITY_DOMAIN %}
|
||||||
|
<!-- Build AD? -->
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="build-app-domain" name="build-app-domain">Also build an Applicability Domain?
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<!-- Num Neighbors -->
|
||||||
|
<label for="num-neighbors">Number of Neighbors</label>
|
||||||
|
<input id="num-neighbors" name="num-neighbors" type="number" class="form-control" value="5"
|
||||||
|
step="1" min="0" max="10">
|
||||||
|
<!-- Local Compatibility -->
|
||||||
|
<label for="local-compatibility-threshold">Local Compatibility Threshold</label>
|
||||||
|
<input id="local-compatibility-threshold" name="local-compatibility-threshold" type="number"
|
||||||
|
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||||
|
<!-- Reliability -->
|
||||||
|
<label for="reliability-threshold">Reliability Threshold</label>
|
||||||
|
<input id="reliability-threshold" name="reliability-threshold" type="number"
|
||||||
|
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<!-- Rule Based Based Form-->
|
<!-- Rule Based Based Form-->
|
||||||
<div id="rule-based-relative-reasoning-specific-form">
|
<div id="rule-based-relative-reasoning-specific-form">
|
||||||
@ -118,47 +140,9 @@
|
|||||||
<!-- EnviFormer-->
|
<!-- EnviFormer-->
|
||||||
<div id="enviformer-specific-form">
|
<div id="enviformer-specific-form">
|
||||||
<label for="enviformer-threshold">Threshold</label>
|
<label for="enviformer-threshold">Threshold</label>
|
||||||
<input type="number" min="0" , max="1" step="0.05" value="0.5" id="enviformer-threshold"
|
<input type="number" min="0" max="1" step="0.05" value="0.5" id="enviformer-threshold"
|
||||||
name="enviformer-threshold" class="form-control">
|
name="enviformer-threshold" class="form-control">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if 'applicability_domain' in enabled_features %}
|
|
||||||
<div class="modal-body hide" data-step="3" data-title="Advanced Options II">
|
|
||||||
<div class="jumbotron">Selection of parameter values for the Applicability Domain process.
|
|
||||||
Number of Neighbours refers to a requirement on the minimum number of compounds from the
|
|
||||||
training
|
|
||||||
dataset that has at least one triggered transformation rule that is common with the compound
|
|
||||||
being
|
|
||||||
analyzed.
|
|
||||||
Reliability Threshold is a requirement on the average tanimoto distance to the set number of
|
|
||||||
"nearest neighbours" (Number of neighbours with the smallest tanimoto distances).
|
|
||||||
Local Compatibility Threshold is a requirement on the average F1 score determined from the
|
|
||||||
number of
|
|
||||||
nearest neighbours, using their respective precision and recall values computed from the
|
|
||||||
agreement
|
|
||||||
between their observed and triggered rules.
|
|
||||||
You can learn more about it in our wiki!
|
|
||||||
</div>
|
|
||||||
<!-- Use AD? -->
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
<input type="checkbox" id="buildAD" name="buildAD">Also build an Applicability Domain?
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<!-- Num Neighbours -->
|
|
||||||
<label for="adK">Number of Neighbours</label>
|
|
||||||
<input id="adK" name="adK" type="number" class="form-control" value="5" step="1" min="0"
|
|
||||||
max="10">
|
|
||||||
<!-- F1 Threshold -->
|
|
||||||
<label for="localCompatibilityThreshold">Local Compatibility Threshold</label>
|
|
||||||
<input id="localCompatibilityThreshold" name="localCompatibilityThreshold" type="number"
|
|
||||||
class="form-control" value="0.5" step="0.01" min="0" max="1">
|
|
||||||
<!-- Percentile Threshold -->
|
|
||||||
<label for="reliabilityThreshold">Reliability Threshold</label>
|
|
||||||
<input id="reliabilityThreshold" name="reliabilityThreshold" type="number" class="form-control"
|
|
||||||
value="0.5" step="0.01" min="0" max="1">
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@ -179,6 +163,9 @@ $(function() {
|
|||||||
$("#ml-relative-reasoning-rule-packages").selectpicker();
|
$("#ml-relative-reasoning-rule-packages").selectpicker();
|
||||||
$("#ml-relative-reasoning-data-packages").selectpicker();
|
$("#ml-relative-reasoning-data-packages").selectpicker();
|
||||||
$("#ml-relative-reasoning-evaluation-packages").selectpicker();
|
$("#ml-relative-reasoning-evaluation-packages").selectpicker();
|
||||||
|
if ($('#ml-relative-reasoning-additional-fingerprinter').length > 0) {
|
||||||
|
$("#ml-relative-reasoning-additional-fingerprinter").selectpicker();
|
||||||
|
}
|
||||||
|
|
||||||
// On change hide all and show only selected
|
// On change hide all and show only selected
|
||||||
$("#model-type").change(function() {
|
$("#model-type").change(function() {
|
||||||
|
|||||||
@ -1,38 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Delete Group -->
|
|
||||||
<div id="delete_group_modal" class="modal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title">Delete Group</h3>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
Clicking "Delete" will <strong>permanently</strong> delete the Group.
|
|
||||||
This action can't be undone!
|
|
||||||
</div>
|
|
||||||
<form id="delete-group-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="hidden" value="delete-group">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-danger" id="delete-group-modal-submit">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
|
|
||||||
$('#delete-group-modal-submit').click(function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$('#delete-group-modal-form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Delete Model -->
|
|
||||||
<div id="delete_model_modal" class="modal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title">Delete Model</h3>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
Deletes the Model.
|
|
||||||
<form id="delete-model-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-model"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-primary" id="delete-model-modal-submit">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
|
|
||||||
$('#delete-model-modal-submit').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$('#delete-model-modal-form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Delete Node -->
|
|
||||||
<div id="delete_node_modal" class="modal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title">Delete Node</h3>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
Deletes the Node as well as ingoing and outgoing edges.
|
|
||||||
<form id="delete-node-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-node"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-primary" id="delete-node-modal-submit">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
|
|
||||||
$('#delete-node-modal-submit').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$('#delete-node-modal-form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Delete Package -->
|
|
||||||
<div id="delete_package_modal" class="modal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title">Delete Package</h3>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
Deleting a Package deletes the very Package
|
|
||||||
as well as all Objects stored in the Package.
|
|
||||||
<form id="delete-package-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-package"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-primary" id="delete-package-modal-submit">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
|
|
||||||
$('#delete-package-modal-submit').click(function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$('#delete-package-modal-form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -22,7 +22,7 @@
|
|||||||
<option value="{{ e.url }}">{{ e.edge_label.name }}</option>
|
<option value="{{ e.url }}">{{ e.edge_label.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-edge"/>
|
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
||||||
</form>
|
</form>
|
||||||
<p></p>
|
<p></p>
|
||||||
<div id="delete_pathway_edge_image"></div>
|
<div id="delete_pathway_edge_image"></div>
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
<option value="{{ n.url }}">{{ n.default_node_label.name }}</option>
|
<option value="{{ n.url }}">{{ n.default_node_label.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-node"/>
|
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
||||||
</form>
|
</form>
|
||||||
<p></p>
|
<p></p>
|
||||||
<div id="delete_pathway_node_image"></div>
|
<div id="delete_pathway_node_image"></div>
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Delete Reaction -->
|
|
||||||
<div id="delete_reaction_modal" class="modal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title">Delete Reaction</h3>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
Deletes the Reaction.
|
|
||||||
<form id="delete-reaction-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-reaction"/>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-primary" id="delete-reaction-modal-submit">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
|
|
||||||
$('#delete-reaction-modal-submit').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
$('#delete-reaction-modal-form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!-- Delete User -->
|
|
||||||
<div id="delete_user_modal" class="modal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3 class="modal-title">Delete User</h3>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="alert alert-danger">
|
|
||||||
Clicking "Delete" will <strong>permanently</strong> delete the User and associated data.
|
|
||||||
This action can't be undone!
|
|
||||||
</div>
|
|
||||||
<form id="delete-user-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="hidden" value="delete-user">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
|
||||||
<button type="button" class="btn btn-danger" id="delete-user-modal-submit">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
|
|
||||||
$('#delete-user-modal-submit').click(function(e){
|
|
||||||
e.preventDefault();
|
|
||||||
$('#delete-user-modal-form').submit();
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
@ -1,24 +1,24 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
<!-- Delete Pathway -->
|
<!-- Download Pathway -->
|
||||||
<div id="delete_pathway_modal" class="modal" tabindex="-1">
|
<div id="download_pathway_modal" class="modal" tabindex="-1">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title">Delete Pathway</h3>
|
<h3 class="modal-title">Download Pathway</h3>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Deletes the Pathway together with all Nodes and Edges.
|
By clicking on Download the Pathway will be converted into a CSV and directly downloaded.
|
||||||
<form id="delete-pathway-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
<form id="download-pathway-modal-form" accept-charset="UTF-8" action="{{ pathway.url }}"
|
||||||
{% csrf_token %}
|
data-remote="true" method="GET">
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-pathway"/>
|
<input type="hidden" name="download" value="true"/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
<button type="button" class="btn btn-primary" id="delete-pathway-modal-submit">Delete</button>
|
<button type="button" class="btn btn-primary" id="download-pathway-modal-submit">Download</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -26,9 +26,10 @@
|
|||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
$('#delete-pathway-modal-submit').click(function (e) {
|
$('#download-pathway-modal-submit').click(function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$('#delete-pathway-modal-form').submit();
|
$('#download-pathway-modal-form').submit();
|
||||||
|
$('#download_pathway_modal').modal('hide');
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
42
templates/modals/objects/generic_delete_modal.html
Normal file
42
templates/modals/objects/generic_delete_modal.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!-- Delete Object -->
|
||||||
|
<div id="generic_delete_modal" class="modal" tabindex="-1">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h3 class="modal-title">Delete {{ object_type|capfirst }}</h3>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
{% if object_type == 'user' %}
|
||||||
|
Clicking "Delete" will <strong>permanently</strong> delete the User and associated data.
|
||||||
|
This action can't be undone!
|
||||||
|
{% else %}
|
||||||
|
Deletes the {{ object_type|capfirst }}. Related objects that depend on this {{ object_type|capfirst }}
|
||||||
|
will be deleted as well.
|
||||||
|
{% endif %}
|
||||||
|
<form id="generic-delete-modal-form" accept-charset="UTF-8" action="{{ current_object.url }}"
|
||||||
|
data-remote="true" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="hidden" id="hidden" name="hidden" value="delete"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="generic-delete-modal-form-submit">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
|
||||||
|
$('#generic-delete-modal-form-submit').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#generic-delete-modal-form').submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
</script>
|
||||||
72
templates/modals/objects/generic_set_scenario_modal.html
Normal file
72
templates/modals/objects/generic_set_scenario_modal.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{% load static %}
|
||||||
|
<div class="modal fade bs-modal-lg" id="set_scenario_modal" tabindex="-1" aria-labelledby="set_scenario_modal"
|
||||||
|
aria-modal="true" role="dialog">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
<h4 class="modal-title">Set Scenarios for {{ current_object.name }}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div id="loading_scenario_div" class="text-center"></div>
|
||||||
|
<form id="set_scenario_modal_form" accept-charset="UTF-8" action="{{ current_object.url }}"
|
||||||
|
data-remote="true" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<label for="scenario-select">Scenarios</label>
|
||||||
|
<select id="scenario-select" name="selected-scenarios" data-actions-box='true' class="form-control"
|
||||||
|
multiple data-width='100%'>
|
||||||
|
<option disabled>Select Scenarios</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary pull-left" data-dismiss="modal">Close
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="set_scenario_modal_form_submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$(function () {
|
||||||
|
var loaded = false;
|
||||||
|
|
||||||
|
var attachedScenarios = []
|
||||||
|
{% if current_object.scenarios.all %}
|
||||||
|
{% for scen in current_object.scenarios.all %}
|
||||||
|
attachedScenarios.push('{{ scen.url }}')
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
$('#scenario-select').selectpicker();
|
||||||
|
|
||||||
|
$('#set_scenario_modal').on('shown.bs.modal', function () {
|
||||||
|
|
||||||
|
if (!loaded) {
|
||||||
|
makeLoadingGif("#loading_scenario_div", "{% static '/images/wait.gif' %}");
|
||||||
|
$('#loading_scenario_div').append("<p></p><div class='alert alert-info'>Loading Scenarios...</div>");
|
||||||
|
|
||||||
|
$.getJSON("{% url 'package scenario list' meta.current_package.uuid %}").then(function (data) {
|
||||||
|
for(s in data) {
|
||||||
|
scenario = data[s]
|
||||||
|
var selected = attachedScenarios.includes(scenario.url);
|
||||||
|
$('#scenario-select').append(`<option value="${scenario.url}" ${selected ? 'selected' : ''}>${scenario.name}</option>`);
|
||||||
|
}
|
||||||
|
$('#scenario-select').selectpicker('refresh');
|
||||||
|
$("#loading_scenario_div").empty();
|
||||||
|
});
|
||||||
|
loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#set_scenario_modal_form_submit').on('click', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$('#set_scenario_modal_form').submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
@ -1,24 +1,24 @@
|
|||||||
{% load static %}
|
{% load static %}
|
||||||
<!-- Delete Compound -->
|
<!-- Publish a Package -->
|
||||||
<div id="delete_compound_modal" class="modal" tabindex="-1">
|
<div id="publish_package_modal" class="modal" tabindex="-1">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3 class="modal-title">Delete Compound</h3>
|
<h5 class="modal-title">Publish Package</h5>
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
<span aria-hidden="true">×</span>
|
<span aria-hidden="true">×</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
Deletes the Compound and associated Structures.
|
<p>Clicking on Publish will make this Package publicly available!</p>
|
||||||
<form id="delete-compound-modal-form" accept-charset="UTF-8" action="" data-remote="true" method="post">
|
<form id="publish-package-modal-form" accept-charset="UTF-8" action="{{ current_package.url }}" data-remote="true" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input type="hidden" id="hidden" name="hidden" value="delete-compound"/>
|
<input type="hidden" name="hidden" value="publish-package">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
|
||||||
<button type="button" class="btn btn-primary" id="delete-compound-modal-submit">Delete</button>
|
<button type="button" class="btn btn-primary" id="publish-package-modal-form-submit">Publish</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -26,9 +26,9 @@
|
|||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|
||||||
$('#delete-compound-modal-submit').click(function(e){
|
$('#publish-package-modal-form-submit').click(function(e){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
$('#delete-compound-modal-form').submit();
|
$('#publish-package-modal-form').submit();
|
||||||
});
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
@ -49,6 +49,18 @@
|
|||||||
<iframe id="predict-modal-ketcher" src="{% static '/js/ketcher2/ketcher.html' %}" width="100%"
|
<iframe id="predict-modal-ketcher" src="{% static '/js/ketcher2/ketcher.html' %}" width="100%"
|
||||||
height="510"></iframe>
|
height="510"></iframe>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<label for="prediction-setting">Default Prediction Setting</label>
|
||||||
|
<select id="prediction-setting" name="prediction-setting" class="form-control"
|
||||||
|
data-width='100%'>
|
||||||
|
<option disabled>Select a Setting</option>
|
||||||
|
{% for s in meta.available_settings %}
|
||||||
|
<option value="{{ s.url }}"{% if s.id == meta.user.default_setting.id %}selected{% endif %}>
|
||||||
|
{{ s.name }}{% if s.id == meta.user.default_setting.id %} <i>(User default)</i>{% endif %}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_rule_modal.html" %}
|
{% include "modals/objects/edit_rule_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="rule-detail">
|
<div class="panel-group" id="rule-detail">
|
||||||
@ -49,7 +51,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Scenarios -->
|
||||||
|
{% if rule.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="rule-scenario-link" data-toggle="collapse" data-parent="#rule-detail"
|
||||||
|
href="#rule-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="rule-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in rule.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- EC Numbers -->
|
<!-- EC Numbers -->
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
|||||||
@ -5,7 +5,8 @@
|
|||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_compound_modal.html" %}
|
{% include "modals/objects/edit_compound_modal.html" %}
|
||||||
{% include "modals/objects/add_structure_modal.html" %}
|
{% include "modals/objects/add_structure_modal.html" %}
|
||||||
{% include "modals/objects/delete_compound_modal.html" %}
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="compound-detail">
|
<div class="panel-group" id="compound-detail">
|
||||||
@ -134,7 +135,69 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Scenarios -->
|
||||||
|
{% if compound.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="compound-scenario-link" data-toggle="collapse" data-parent="#compound-detail"
|
||||||
|
href="#compound-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="compound-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in compound.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- External Identifiers -->
|
<!-- External Identifiers -->
|
||||||
|
{% if compound.get_external_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="compound-external-identifier-link" data-toggle="collapse" data-parent="#compound-detail"
|
||||||
|
href="#compound-external-identifier">External Identifier</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="compound-external-identifier" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% if compound.get_pubchem_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
|
style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="compound-pubchem-identifier-link" data-toggle="collapse"
|
||||||
|
data-parent="#compound-external-identifier"
|
||||||
|
href="#compound-pubchem-identifier">PubChem Compound Identifier</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="compound-pubchem-identifier" class="panel-collapse collapse in">
|
||||||
|
{% for eid in compound.get_pubchem_identifiers %}
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="{{ eid.external_url }}">CID{{ eid.identifier_value }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if compound.get_chebi_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
|
style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="compound-chebi-identifier-link" data-toggle="collapse"
|
||||||
|
data-parent="#compound-external-identifier"
|
||||||
|
href="#compound-chebi-identifier">ChEBI Identifier</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="compound-chebi-identifier" class="panel-collapse collapse in">
|
||||||
|
{% for eid in compound.get_chebi_identifiers %}
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="{{ eid.external_url }}">CHEBI:{{ eid.identifier_value }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_compound_structure_modal.html" %}
|
{% include "modals/objects/edit_compound_structure_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="compound-structure-detail">
|
<div class="panel-group" id="compound-structure-detail">
|
||||||
@ -54,6 +56,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if compound_structure.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="compound_structure-scenario-link" data-toggle="collapse" data-parent="#compound-structure-detail"
|
||||||
|
href="#compound-structure-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="compound-structure-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in compound_structure.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- Reactions -->
|
<!-- Reactions -->
|
||||||
|
|
||||||
<!-- Pathways -->
|
<!-- Pathways -->
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{# {% include "modals/objects/edit_edge_modal.html" %}#}
|
{# {% include "modals/objects/edit_edge_modal.html" %}#}
|
||||||
{# {% include "modals/objects/delete_edge_modal.html" %}#}
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="edge-detail">
|
<div class="panel-group" id="edge-detail">
|
||||||
@ -19,7 +20,7 @@
|
|||||||
style="padding-right:1em"></span></a>
|
style="padding-right:1em"></span></a>
|
||||||
<ul id="actionsList" class="dropdown-menu">
|
<ul id="actionsList" class="dropdown-menu">
|
||||||
{% block actions %}
|
{% block actions %}
|
||||||
{# {% include "actions/objects/edge.html" %}#}
|
{% include "actions/objects/edge.html" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -103,6 +104,21 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if edge.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="edge-scenario-link" data-toggle="collapse" data-parent="#edge-detail"
|
||||||
|
href="#edge-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="edge-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in edge.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_group_modal.html" %}
|
{% include "modals/objects/edit_group_modal.html" %}
|
||||||
{% include "modals/objects/edit_group_member_modal.html" %}
|
{% include "modals/objects/edit_group_member_modal.html" %}
|
||||||
{% include "modals/objects/delete_group_modal.html" %}
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="package-detail">
|
<div class="panel-group" id="package-detail">
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/delete_model_modal.html" %}
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<!-- Include required libs -->
|
<!-- Include required libs -->
|
||||||
@ -90,6 +90,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if model.ready_for_prediction %}
|
||||||
<!-- Predict Panel -->
|
<!-- Predict Panel -->
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
@ -106,11 +107,36 @@
|
|||||||
<button class="btn btn-default" type="submit" id="predict-button">Predict!</button>
|
<button class="btn btn-default" type="submit" id="predict-button">Predict!</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="loading"></div>
|
<div id="predictLoading"></div>
|
||||||
<div id="predictResultTable"></div>
|
<div id="predictResultTable"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- End Predict Panel -->
|
<!-- End Predict Panel -->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if model.app_domain %}
|
||||||
|
<!-- App Domain -->
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="app-domain-assessment-link" data-toggle="collapse" data-parent="#model-detail"
|
||||||
|
href="#app-domain-assessment">Applicability Domain Assessment</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="app-domain-assessment" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="smiles-to-assess" type="text" class="form-control" placeholder="CCN(CC)C(=O)C1=CC(=CC=C1)C">
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-default" type="submit" id="assess-button">Assess!</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div id="appDomainLoading"></div>
|
||||||
|
<div id="appDomainAssessmentResultTable"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- End App Domain -->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if model.model_status == 'FINISHED' %}
|
{% if model.model_status == 'FINISHED' %}
|
||||||
<!-- Single Gen Curve Panel -->
|
<!-- Single Gen Curve Panel -->
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
@ -243,7 +269,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
function handleResponse(data) {
|
function handlePredictionResponse(data) {
|
||||||
res = "<table class='table table-striped'>"
|
res = "<table class='table table-striped'>"
|
||||||
res += "<thead>"
|
res += "<thead>"
|
||||||
res += "<th scope='col'>#</th>"
|
res += "<th scope='col'>#</th>"
|
||||||
@ -277,9 +303,9 @@
|
|||||||
$("#predictResultTable").append(res);
|
$("#predictResultTable").append(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear() {
|
function clear(divid) {
|
||||||
$("#predictResultTable").removeClass("alert alert-danger");
|
$("#" + divid).removeClass("alert alert-danger");
|
||||||
$("#predictResultTable").empty();
|
$("#" + divid).empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($('#predict-button').length > 0) {
|
if ($('#predict-button').length > 0) {
|
||||||
@ -291,32 +317,70 @@
|
|||||||
"classify": "ILikeCats!"
|
"classify": "ILikeCats!"
|
||||||
}
|
}
|
||||||
|
|
||||||
clear();
|
clear("predictResultTable");
|
||||||
|
|
||||||
makeLoadingGif("#loading", "{% static '/images/wait.gif' %}");
|
makeLoadingGif("#predictLoading", "{% static '/images/wait.gif' %}");
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: 'get',
|
type: 'get',
|
||||||
data: data,
|
data: data,
|
||||||
url: '',
|
url: '',
|
||||||
success: function (data, textStatus) {
|
success: function (data, textStatus) {
|
||||||
try {
|
try {
|
||||||
$("#loading").empty();
|
$("#predictLoading").empty();
|
||||||
handleResponse(data);
|
handlePredictionResponse(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Error");
|
console.log("Error");
|
||||||
$("#loading").empty();
|
$("#predictLoading").empty();
|
||||||
$("#predictResultTable").addClass("alert alert-danger");
|
$("#predictResultTable").addClass("alert alert-danger");
|
||||||
$("#predictResultTable").append("Error while processing request :/");
|
$("#predictResultTable").append("Error while processing request :/");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error: function (jqXHR, textStatus, errorThrown) {
|
error: function (jqXHR, textStatus, errorThrown) {
|
||||||
$("#loading").empty();
|
$("#predictLoading").empty();
|
||||||
$("#predictResultTable").addClass("alert alert-danger");
|
$("#predictResultTable").addClass("alert alert-danger");
|
||||||
$("#predictResultTable").append("Error while processing request :/");
|
$("#predictResultTable").append("Error while processing request :/");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($('#assess-button').length > 0) {
|
||||||
|
$("#assess-button").on("click", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"smiles": $("#smiles-to-assess").val(),
|
||||||
|
"app-domain-assessment": "ILikeCats!"
|
||||||
|
}
|
||||||
|
|
||||||
|
clear("appDomainAssessmentResultTable");
|
||||||
|
|
||||||
|
makeLoadingGif("#appDomainLoading", "{% static '/images/wait.gif' %}");
|
||||||
|
$.ajax({
|
||||||
|
type: 'get',
|
||||||
|
data: data,
|
||||||
|
url: '',
|
||||||
|
success: function (data, textStatus) {
|
||||||
|
try {
|
||||||
|
$("#appDomainLoading").empty();
|
||||||
|
handleAssessmentResponse("{% url 'depict' %}", data);
|
||||||
|
console.log(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error");
|
||||||
|
$("#appDomainLoading").empty();
|
||||||
|
$("#appDomainAssessmentResultTable").addClass("alert alert-danger");
|
||||||
|
$("#appDomainAssessmentResultTable").append("Error while processing request :/");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function (jqXHR, textStatus, errorThrown) {
|
||||||
|
$("#appDomainLoading").empty();
|
||||||
|
$("#appDomainAssessmentResultTable").addClass("alert alert-danger");
|
||||||
|
$("#appDomainAssessmentResultTable").append("Error while processing request :/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_node_modal.html" %}
|
{% include "modals/objects/edit_node_modal.html" %}
|
||||||
{% include "modals/objects/delete_node_modal.html" %}
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="node-detail">
|
<div class="panel-group" id="node-detail">
|
||||||
@ -69,7 +70,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if node.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="node-scenario-link" data-toggle="collapse" data-parent="#node-detail"
|
||||||
|
href="#node-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="node-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in node.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if app_domain_assessment_data %}
|
||||||
|
<div id="appDomainAssessmentResultTable"></div>
|
||||||
|
<script>
|
||||||
|
$(document).ready(function () {
|
||||||
|
handleAssessmentResponse("{% url 'depict' %}", {{ app_domain_assessment_data|safe }})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -5,8 +5,9 @@
|
|||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_package_modal.html" %}
|
{% include "modals/objects/edit_package_modal.html" %}
|
||||||
{% include "modals/objects/edit_package_permissions_modal.html" %}
|
{% include "modals/objects/edit_package_permissions_modal.html" %}
|
||||||
|
{% include "modals/objects/publish_package_modal.html" %}
|
||||||
{% include "modals/objects/set_license_modal.html" %}
|
{% include "modals/objects/set_license_modal.html" %}
|
||||||
{% include "modals/objects/delete_package_modal.html" %}
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="package-detail">
|
<div class="panel-group" id="package-detail">
|
||||||
@ -52,23 +53,5 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if package.license %}
|
|
||||||
<p></p>
|
|
||||||
<div class="panel-group" id="license_accordion">
|
|
||||||
<div class="panel panel-default list-group-item" style="background-color:#f5f5f5">
|
|
||||||
<div class="panel-title">
|
|
||||||
<a data-toggle="collapse" data-parent="#licence_accordion" href="#license">License</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="license" class="panel-collapse collapse in">
|
|
||||||
<div class="panel-body list-group-item">
|
|
||||||
<a target="_blank" href="{{ package.license.link }}">
|
|
||||||
<img src="{{ package.license.image_link }}">
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -4,16 +4,22 @@
|
|||||||
|
|
||||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||||
<style>
|
<style>
|
||||||
svg {
|
#vizdiv {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 600px;
|
height: 600px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pwsvg {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.link {
|
.link {
|
||||||
stroke: #999;
|
stroke: #999;
|
||||||
stroke-opacity: 0.6;
|
stroke-opacity: 0.6;
|
||||||
marker-end: url(#arrow);
|
//marker-end: url(#arrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.link_no_arrow {
|
.link_no_arrow {
|
||||||
@ -31,6 +37,31 @@
|
|||||||
stroke-width: 1.5px;
|
stroke-width: 1.5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inside_app_domain {
|
||||||
|
fill: green;
|
||||||
|
stroke: green;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outside_app_domain {
|
||||||
|
fill: red;
|
||||||
|
stroke: red;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.passes_app_domain {
|
||||||
|
stroke: green;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
stroke-opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fails_app_domain {
|
||||||
|
stroke: red;
|
||||||
|
stroke-width: 1.5px;
|
||||||
|
stroke-opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.highlighted {
|
.highlighted {
|
||||||
stroke: red;
|
stroke: red;
|
||||||
stroke-width: 3px;
|
stroke-width: 3px;
|
||||||
@ -50,10 +81,12 @@
|
|||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/add_pathway_node_modal.html" %}
|
{% include "modals/objects/add_pathway_node_modal.html" %}
|
||||||
{% include "modals/objects/add_pathway_edge_modal.html" %}
|
{% include "modals/objects/add_pathway_edge_modal.html" %}
|
||||||
|
{% include "modals/objects/download_pathway_modal.html" %}
|
||||||
{% include "modals/objects/edit_pathway_modal.html" %}
|
{% include "modals/objects/edit_pathway_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
{% include "modals/objects/delete_pathway_node_modal.html" %}
|
{% include "modals/objects/delete_pathway_node_modal.html" %}
|
||||||
{% include "modals/objects/delete_pathway_edge_modal.html" %}
|
{% include "modals/objects/delete_pathway_edge_modal.html" %}
|
||||||
{% include "modals/objects/delete_pathway_modal.html" %}
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<p></p>
|
<p></p>
|
||||||
@ -79,8 +112,7 @@
|
|||||||
<ul class="nav navbar-nav">
|
<ul class="nav navbar-nav">
|
||||||
<li class="dropdown requiresWritePerm">
|
<li class="dropdown requiresWritePerm">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true" aria-expanded="false">
|
||||||
aria-expanded="false">
|
|
||||||
<span class="glyphicon glyphicon-edit"></span>
|
<span class="glyphicon glyphicon-edit"></span>
|
||||||
Edit
|
Edit
|
||||||
<span class="caret"></span></a>
|
<span class="caret"></span></a>
|
||||||
@ -90,11 +122,26 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
{% if pathway.setting.model.app_domain %}
|
||||||
|
<li class="dropdown">
|
||||||
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
|
||||||
|
aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="glyphicon glyphicon-eye-open"></span>
|
||||||
|
View
|
||||||
|
<span class="caret"></span></a>
|
||||||
|
<ul id="editingList" class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a class="button" id="app-domain-toggle-button">
|
||||||
|
<i id="app-domain-toggle-button" class="glyphicon glyphicon-eye-open"></i> App Domain View</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li>
|
<li>
|
||||||
<a role="button" data-toggle="modal" onclick="goFullscreen('pwcontent')">
|
<a role="button" data-toggle="modal" onclick="goFullscreen('vizdiv')">
|
||||||
<span class="glyphicon glyphicon-fullscreen"></span>
|
<span class="glyphicon glyphicon-fullscreen"></span>
|
||||||
Fullscreen
|
Fullscreen
|
||||||
</a>
|
</a>
|
||||||
@ -126,15 +173,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div id="vizdiv" >
|
<div id="vizdiv" >
|
||||||
<svg width="2000" height="2000">
|
<svg id="pwsvg">
|
||||||
{% if debug %}
|
{% if debug %}
|
||||||
<rect width="100%" height="100%" fill="aliceblue"/>
|
<rect width="100%" height="100%" fill="aliceblue"/>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<defs>
|
<defs>
|
||||||
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
<marker id="arrow" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
orient="auto-start-reverse">
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="#999"/>
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="#999"/>
|
||||||
</marker>
|
</marker>
|
||||||
|
<marker id="arrow_passes_app_domain" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="green"/>
|
||||||
|
</marker>
|
||||||
|
<marker id="arrow_fails_app_domain" viewBox="0 0 10 10" refX="43" refY="5" markerWidth="6" markerHeight="6"
|
||||||
|
orient="auto-start-reverse" markerUnits="userSpaceOnUse">
|
||||||
|
<path d="M 0 0 L 10 5 L 0 10 z" fill="red"/>
|
||||||
|
</marker>
|
||||||
</defs>
|
</defs>
|
||||||
<g id="zoomable"></g>
|
<g id="zoomable"></g>
|
||||||
</svg>
|
</svg>
|
||||||
@ -153,13 +208,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if pathway.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="pathway-scenario-link" data-toggle="collapse" data-parent="#pathway-detail"
|
||||||
|
href="#pathway-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="pathway-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in pathway.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if pathway.setting %}
|
{% if pathway.setting %}
|
||||||
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
<h4 class="panel-title">
|
<h4 class="panel-title">
|
||||||
<a id="pathwaySettingLink" data-toggle="collapse" data-parent="#pathwayAccordion"
|
<a id="pathwaySettingLink" data-toggle="collapse" data-parent="#pathwayAccordion"
|
||||||
href="#pathwaySetting">Setting</a></h4>
|
href="#pathwaySetting">Setting</a></h4>
|
||||||
</div>
|
</div>
|
||||||
<div id="pathwaySetting" class="panel-collapse collapse in">
|
<div id="pathwaySetting" class="panel-collapse collapse">
|
||||||
<div class="panel-body list-group-item" id="pathwaySettingContent">
|
<div class="panel-body list-group-item" id="pathwaySettingContent">
|
||||||
<table class="table table-bordered table-hover">
|
<table class="table table-bordered table-hover">
|
||||||
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
<tr style="background-color: rgba(0, 0, 0, 0.08);">
|
||||||
@ -245,6 +316,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
|
// Globla switch for app domain view
|
||||||
|
var appDomainViewEnabled = false;
|
||||||
|
|
||||||
function goFullscreen(id) {
|
function goFullscreen(id) {
|
||||||
var element = document.getElementById(id);
|
var element = document.getElementById(id);
|
||||||
@ -266,6 +339,51 @@
|
|||||||
// TODO fix somewhere else...
|
// TODO fix somewhere else...
|
||||||
var newDesc = transformReferences($('#DescriptionContent')[0].innerText);
|
var newDesc = transformReferences($('#DescriptionContent')[0].innerText);
|
||||||
$('#DescriptionContent').html(newDesc);
|
$('#DescriptionContent').html(newDesc);
|
||||||
|
|
||||||
|
|
||||||
|
$('#app-domain-toggle-button').on('click', function () {
|
||||||
|
// glyphicon glyphicon-eye-close
|
||||||
|
// glyphicon glyphicon-eye-open
|
||||||
|
appDomainViewEnabled = !appDomainViewEnabled;
|
||||||
|
|
||||||
|
if (appDomainViewEnabled) {
|
||||||
|
$('#app-domain-toggle-button > i').removeClass('glyphicon-eye-open');
|
||||||
|
$('#app-domain-toggle-button > i').addClass('glyphicon-eye-close');
|
||||||
|
nodes.forEach((x) => {
|
||||||
|
if(x.app_domain) {
|
||||||
|
if (x.app_domain.inside_app_domain) {
|
||||||
|
d3.select(x.el).select("circle").classed("inside_app_domain", true);
|
||||||
|
} else {
|
||||||
|
d3.select(x.el).select("circle").classed("outside_app_domain", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
links.forEach((x) => {
|
||||||
|
if(x.app_domain) {
|
||||||
|
if (x.app_domain.passes_app_domain) {
|
||||||
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow_passes_app_domain)");
|
||||||
|
d3.select(x.el).classed("passes_app_domain", true);
|
||||||
|
} else {
|
||||||
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow_fails_app_domain)");
|
||||||
|
d3.select(x.el).classed("fails_app_domain", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$('#app-domain-toggle-button > i').removeClass('glyphicon-eye-close');
|
||||||
|
$('#app-domain-toggle-button > i').addClass('glyphicon-eye-open');
|
||||||
|
nodes.forEach((x) => {
|
||||||
|
d3.select(x.el).select("circle").classed("inside_app_domain", false);
|
||||||
|
d3.select(x.el).select("circle").classed("outside_app_domain", false);
|
||||||
|
});
|
||||||
|
links.forEach((x) => {
|
||||||
|
d3.select(x.el).attr("marker-end", d => d.target.pseudo ? "" : "url(#arrow)");
|
||||||
|
d3.select(x.el).classed("passes_app_domain", false);
|
||||||
|
d3.select(x.el).classed("fails_app_domain", false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -4,7 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_reaction_modal.html" %}
|
{% include "modals/objects/edit_reaction_modal.html" %}
|
||||||
{% include "modals/objects/delete_reaction_modal.html" %}
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="reaction-detail">
|
<div class="panel-group" id="reaction-detail">
|
||||||
@ -118,9 +119,70 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if reaction.scenarios.all %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="reaction-scenario-link" data-toggle="collapse" data-parent="#reaction-detail"
|
||||||
|
href="#reaction-scenario">Scenarios</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="reaction-scenario" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% for s in reaction.scenarios.all %}
|
||||||
|
<a class="list-group-item" href="{{ s.url }}">{{ s.name }} <i>({{ s.package.name }})</i></a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- External Identifiers -->
|
||||||
|
{% if reaction.get_external_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item" style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="reaction-external-identifier-link" data-toggle="collapse" data-parent="#reaction-detail"
|
||||||
|
href="#reaction-external-identifier">External Identifier</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="reaction-external-identifier" class="panel-collapse collapse in">
|
||||||
|
<div class="panel-body list-group-item">
|
||||||
|
{% if reaction.get_rhea_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
|
style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="reaction-rhea-identifier-link" data-toggle="collapse"
|
||||||
|
data-parent="#reaction-external-identifier"
|
||||||
|
href="#reaction-rhea-identifier">Rhea</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="reaction-rhea-identifier" class="panel-collapse collapse in">
|
||||||
|
{% for eid in reaction.get_rhea_identifiers %}
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="{{ eid.external_url }}">{{ eid.identifier_value }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if reaction.get_uniprot_identifiers %}
|
||||||
|
<div class="panel panel-default panel-heading list-group-item"
|
||||||
|
style="background-color:silver">
|
||||||
|
<h4 class="panel-title">
|
||||||
|
<a id="reaction-uniprot-identifier-link" data-toggle="collapse"
|
||||||
|
data-parent="#reaction-external-identifier"
|
||||||
|
href="#reaction-uniprot-identifier">UniProt</a>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div id="reaction-uniprot-identifier" class="panel-collapse collapse in">
|
||||||
|
{% for eid in reaction.get_uniprot_identifiers %}
|
||||||
|
<a class="list-group-item"
|
||||||
|
href="{{ eid.external_url }}">10 SwissProt entries ({{ eid.identifier_value }})</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
<div class="panel-group" id="scenario-detail">
|
<div class="panel-group" id="scenario-detail">
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
|
|||||||
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
{% block action_modals %}
|
{% block action_modals %}
|
||||||
{% include "modals/objects/edit_rule_modal.html" %}
|
{% include "modals/objects/edit_rule_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_set_scenario_modal.html" %}
|
||||||
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="rule-detail">
|
<div class="panel-group" id="rule-detail">
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
{% include "modals/objects/edit_password_modal.html" %}
|
{% include "modals/objects/edit_password_modal.html" %}
|
||||||
{% include "modals/collections/new_prediction_setting_modal.html" %}
|
{% include "modals/collections/new_prediction_setting_modal.html" %}
|
||||||
{% include "modals/objects/manage_api_token_modal.html" %}
|
{% include "modals/objects/manage_api_token_modal.html" %}
|
||||||
{% include "modals/objects/delete_user_modal.html" %}
|
{% include "modals/objects/generic_delete_modal.html" %}
|
||||||
{% endblock action_modals %}
|
{% endblock action_modals %}
|
||||||
|
|
||||||
<div class="panel-group" id="user-detail">
|
<div class="panel-group" id="user-detail">
|
||||||
|
|||||||
@ -79,6 +79,10 @@
|
|||||||
|
|
||||||
allEmpty = true;
|
allEmpty = true;
|
||||||
for (key in data) {
|
for (key in data) {
|
||||||
|
if (key === 'searchterm') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (data[key].length < 1) {
|
if (data[key].length < 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -176,8 +180,16 @@
|
|||||||
$("#selPackages").selectpicker();
|
$("#selPackages").selectpicker();
|
||||||
$("#search-button").on("click", search);
|
$("#search-button").on("click", search);
|
||||||
|
|
||||||
|
$("#searchbar").on("keydown", function (e) {
|
||||||
|
if (e.key === "Enter") {
|
||||||
|
e.preventDefault();
|
||||||
|
search(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
{% if search_result %}
|
{% if search_result %}
|
||||||
|
$('#searchbar').val('{{ search_result.searchterm }}')
|
||||||
handleSearchResponse("results", {{ search_result|safe }});
|
handleSearchResponse("results", {{ search_result|safe }});
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
52
tests/test_dataset.py
Normal file
52
tests/test_dataset.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from epdb.logic import PackageManager
|
||||||
|
from epdb.models import Reaction, Compound, User, Rule
|
||||||
|
from utilities.ml import Dataset
|
||||||
|
|
||||||
|
|
||||||
|
class DatasetTest(TestCase):
|
||||||
|
fixtures = ["test_fixture.cleaned.json"]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.cs1 = Compound.create(
|
||||||
|
self.package,
|
||||||
|
name='2,6-Dibromohydroquinone',
|
||||||
|
description='http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1/compound/d6435251-1a54-4327-b4b1-fd6e9a8f4dc9/structure/d8a0225c-dbb5-4e6c-a642-730081c09c5b',
|
||||||
|
smiles='C1=C(C(=C(C=C1O)Br)O)Br',
|
||||||
|
).default_structure
|
||||||
|
|
||||||
|
self.cs2 = Compound.create(
|
||||||
|
self.package,
|
||||||
|
smiles='O=C(O)CC(=O)/C=C(/Br)C(=O)O',
|
||||||
|
).default_structure
|
||||||
|
|
||||||
|
self.rule1 = Rule.create(
|
||||||
|
rule_type='SimpleAmbitRule',
|
||||||
|
package=self.package,
|
||||||
|
smirks='[#8:8]([H])-[c:4]1[c:3]([H])[c:2](-[#1,#17,#35:9])[c:1](-[#8:7]([H]))[c:6](-[#1,#17,#35])[c:5]([H])1>>[#8-]-[#6:6](=O)-[#6:5]-[#6:4](=[O:8])\[#6:3]=[#6:2](\[#1,#17,#35:9])-[#6:1](-[#8-])=[O:7]',
|
||||||
|
description='http://localhost:8000/package/32de3cf4-e3e6-4168-956e-32fa5ddb0ce1/simple-ambit-rule/f6a56c0f-a4a0-4ee3-b006-d765b4767cf6'
|
||||||
|
)
|
||||||
|
|
||||||
|
self.reaction1 = Reaction.create(
|
||||||
|
package=self.package,
|
||||||
|
educts=[self.cs1],
|
||||||
|
products=[self.cs2],
|
||||||
|
rules=[self.rule1],
|
||||||
|
multi_step=False
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(DatasetGeneratorTest, cls).setUpClass()
|
||||||
|
cls.user = User.objects.get(username='anonymous')
|
||||||
|
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
|
||||||
|
|
||||||
|
def test_smoke(self):
|
||||||
|
reactions = [r for r in Reaction.objects.filter(package=self.package)]
|
||||||
|
applicable_rules = [self.rule1]
|
||||||
|
|
||||||
|
ds = Dataset.generate_dataset(reactions, applicable_rules)
|
||||||
|
|
||||||
|
self.assertEqual(len(ds.y()), 1)
|
||||||
|
self.assertEqual(sum(ds.y()[0]), 1)
|
||||||
@ -1,111 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
from epdb.models import ParallelRule
|
|
||||||
from utilities.ml import Compound, Reaction, DatasetGenerator
|
|
||||||
|
|
||||||
|
|
||||||
class CompoundTest(TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.c1 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C", uuid='c1')
|
|
||||||
self.c2 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C", uuid='c2')
|
|
||||||
|
|
||||||
def test_compound_eq_ignores_uuid(self):
|
|
||||||
self.assertEqual(self.c1, self.c2)
|
|
||||||
|
|
||||||
|
|
||||||
class ReactionTest(TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.c1 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C")
|
|
||||||
self.c2 = Compound(smiles="CCN(CCO)C(=O)C1=CC(C)=CC=C1")
|
|
||||||
# self.r1 = Rule(uuid="bt0334")
|
|
||||||
# c1 --r1--> c2
|
|
||||||
self.c3_1 = Compound(smiles="CCNC(=O)C1=CC(C)=CC=C1")
|
|
||||||
self.c3_2 = Compound(smiles="CC=O")
|
|
||||||
# self.r2 = Rule(uuid="bt0243")
|
|
||||||
# c1 --r2--> c3_1, c3_2
|
|
||||||
|
|
||||||
def test_reaction_equality_ignores_uuid(self):
|
|
||||||
r1 = Reaction([self.c1], [self.c2], self.r1, uuid="abc")
|
|
||||||
r2 = Reaction([self.c1], [self.c2], self.r1, uuid="xyz")
|
|
||||||
self.assertEqual(r1, r2)
|
|
||||||
|
|
||||||
def test_reaction_inequality_on_data_change(self):
|
|
||||||
r1 = Reaction([self.c1], [self.c2], self.r1)
|
|
||||||
r2 = Reaction([self.c1], [self.c3_1], self.r1)
|
|
||||||
self.assertNotEqual(r1, r2)
|
|
||||||
|
|
||||||
def test_reaction_is_hashable(self):
|
|
||||||
r = Reaction([self.c1], [self.c2], self.r1)
|
|
||||||
reactions = {r}
|
|
||||||
self.assertIn(Reaction([self.c1], [self.c2], self.r1), reactions)
|
|
||||||
|
|
||||||
def test_rule_is_optional(self):
|
|
||||||
r = Reaction([self.c1], [self.c2])
|
|
||||||
self.assertIsNone(r.rule)
|
|
||||||
|
|
||||||
def test_uuid_is_optional(self):
|
|
||||||
r = Reaction([self.c1], [self.c2], self.r1)
|
|
||||||
self.assertIsNone(r.uuid)
|
|
||||||
|
|
||||||
def test_repr_includes_uuid(self):
|
|
||||||
r = Reaction([self.c1], [self.c2], self.r1, uuid="abc")
|
|
||||||
self.assertIn("abc", repr(r))
|
|
||||||
|
|
||||||
def test_reaction_equality_with_multiple_compounds_different_ordering(self):
|
|
||||||
r1 = Reaction([self.c1], [self.c3_1, self.c3_2], self.r2)
|
|
||||||
r2 = Reaction([self.c1], [self.c3_2, self.c3_1], self.r2)
|
|
||||||
|
|
||||||
self.assertEqual(r1, r2, "Reaction equality should not rely on list order")
|
|
||||||
|
|
||||||
|
|
||||||
class RuleTest(TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
pass
|
|
||||||
# self.r1 = Rule(uuid="bt0334")
|
|
||||||
# self.r2 = Rule(uuid="bt0243")
|
|
||||||
|
|
||||||
|
|
||||||
class DatasetGeneratorTest(TestCase):
|
|
||||||
fixtures = ['bootstrap.json']
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.c1 = Compound(smiles="CCN(CC)C(=O)C1=CC(=CC=C1)C")
|
|
||||||
self.c2 = Compound(smiles="CCN(CCO)C(=O)C1=CC(C)=CC=C1")
|
|
||||||
self.c3_1 = Compound(smiles="CCNC(=O)C1=CC(C)=CC=C1")
|
|
||||||
self.c3_2 = Compound(smiles="CC=O")
|
|
||||||
|
|
||||||
# self.r1 = Rule(uuid="bt0334") # trig
|
|
||||||
# self.r2 = Rule(uuid="bt0243") # trig
|
|
||||||
# self.r3 = Rule(uuid="bt0003") # no trig
|
|
||||||
|
|
||||||
self.reaction1 = Reaction([self.c1], [self.c2], self.r3)
|
|
||||||
self.reaction2 = Reaction([self.c1], [self.c3_1, self.c3_2], self.r2)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def test_test(self):
|
|
||||||
compounds = [
|
|
||||||
self.c1,
|
|
||||||
self.c2,
|
|
||||||
self.c3_1,
|
|
||||||
self.c3_2,
|
|
||||||
]
|
|
||||||
|
|
||||||
reactions = [
|
|
||||||
self.reaction1,
|
|
||||||
self.reaction2,
|
|
||||||
]
|
|
||||||
|
|
||||||
applicable_rules = [
|
|
||||||
# Rule('bt0334', ParallelRule.objects.get(name='bt0334')),
|
|
||||||
# Rule('bt0243', ParallelRule.objects.get(name='bt0243')),
|
|
||||||
# Rule('bt0003', ParallelRule.objects.get(name='bt0003')),
|
|
||||||
]
|
|
||||||
|
|
||||||
ds = DatasetGenerator.generate_dataset(compounds, reactions, applicable_rules)
|
|
||||||
|
|
||||||
self.assertIsNotNone(ds)
|
|
||||||
55
tests/test_model.py
Normal file
55
tests/test_model.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from epdb.logic import PackageManager
|
||||||
|
from epdb.models import Compound, User, CompoundStructure, Reaction, Rule, MLRelativeReasoning
|
||||||
|
|
||||||
|
|
||||||
|
class ModelTest(TestCase):
|
||||||
|
fixtures = ["test_fixture.cleaned.json"]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
super(ModelTest, cls).setUpClass()
|
||||||
|
cls.user = User.objects.get(username='anonymous')
|
||||||
|
cls.package = PackageManager.create_package(cls.user, 'Anon Test Package', 'No Desc')
|
||||||
|
bbd_data = json.load(open('fixtures/packages/2025-07-18/EAWAG-BBD.json'))
|
||||||
|
cls.BBD = PackageManager.import_package(bbd_data, cls.user)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_smoke(self):
|
||||||
|
threshold = float(0.5)
|
||||||
|
|
||||||
|
# get Package objects from urls
|
||||||
|
rule_package_objs = [self.BBD]
|
||||||
|
data_package_objs = [self.BBD]
|
||||||
|
eval_packages_objs = []
|
||||||
|
|
||||||
|
mod = MLRelativeReasoning.create(
|
||||||
|
self.package,
|
||||||
|
rule_package_objs,
|
||||||
|
data_package_objs,
|
||||||
|
eval_packages_objs,
|
||||||
|
threshold,
|
||||||
|
'ECC - BBD - 0.5',
|
||||||
|
'Created MLRelativeReasoning in Testcase',
|
||||||
|
)
|
||||||
|
ds = mod.load_dataset()
|
||||||
|
|
||||||
|
mod.build_model()
|
||||||
|
print("Model built!")
|
||||||
|
mod.evaluate_model()
|
||||||
|
print("Model Evaluated")
|
||||||
|
|
||||||
|
results = mod.predict('CCN(CC)C(=O)C1=CC(=CC=C1)C')
|
||||||
|
print(results)
|
||||||
@ -19,9 +19,8 @@ class RuleApplicationTest(TestCase):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
from collections import Counter
|
print(f"\nTotal Errors across Rules {len(cls.error_smiles)}")
|
||||||
# print(Counter(cls.error_smiles))
|
# print(cls.error_smiles)
|
||||||
pass
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
print(f"\nTotal errors {self.total_errors}")
|
print(f"\nTotal errors {self.total_errors}")
|
||||||
@ -36,7 +35,7 @@ class RuleApplicationTest(TestCase):
|
|||||||
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
for comp, ambit_prod in zip(bt_rule['compounds'], bt_rule['products']):
|
||||||
|
|
||||||
smi = comp['smiles']
|
smi = comp['smiles']
|
||||||
products = FormatConverter.apply(smi, smirks, preprocess_smiles=True, bracketize=False)
|
products = FormatConverter.apply(smi, smirks)
|
||||||
|
|
||||||
all_rdkit_prods = []
|
all_rdkit_prods = []
|
||||||
for ps in products:
|
for ps in products:
|
||||||
@ -53,15 +52,15 @@ class RuleApplicationTest(TestCase):
|
|||||||
|
|
||||||
# TODO mode "intersection"
|
# TODO mode "intersection"
|
||||||
# partial_res = (len(set(ambit_smiles).intersection(set(rdkit_smiles))) > 0) or (len(ambit_smiles) == 0)
|
# partial_res = (len(set(ambit_smiles).intersection(set(rdkit_smiles))) > 0) or (len(ambit_smiles) == 0)
|
||||||
# FAILED (failures=42)
|
# FAILED (failures=33)
|
||||||
|
|
||||||
# TODO mode = "full ambit"
|
# TODO mode = "full ambit"
|
||||||
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(ambit_smiles)
|
# partial_res = len(set(ambit_smiles).intersection(set(rdkit_smiles))) == len(ambit_smiles)
|
||||||
# FAILED (failures=52)
|
# FAILED (failures=44)
|
||||||
|
|
||||||
# TODO mode = "equality"
|
# TODO mode = "equality"
|
||||||
partial_res = set(ambit_smiles) == set(rdkit_smiles)
|
partial_res = set(ambit_smiles) == set(rdkit_smiles)
|
||||||
# FAILED (failures=71)
|
# FAILED (failures=64)
|
||||||
|
|
||||||
if len(ambit_smiles) and not partial_res:
|
if len(ambit_smiles) and not partial_res:
|
||||||
print(f"""
|
print(f"""
|
||||||
|
|||||||
@ -12,6 +12,8 @@ from rdkit.Chem import MACCSkeys
|
|||||||
from rdkit.Chem import rdChemReactions
|
from rdkit.Chem import rdChemReactions
|
||||||
from rdkit.Chem.Draw import rdMolDraw2D
|
from rdkit.Chem.Draw import rdMolDraw2D
|
||||||
from rdkit.Chem.MolStandardize import rdMolStandardize
|
from rdkit.Chem.MolStandardize import rdMolStandardize
|
||||||
|
from rdkit.Chem.rdmolops import GetMolFrags
|
||||||
|
from rdkit.Contrib.IFG import ifg
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
RDLogger.DisableLog('rdApp.*')
|
RDLogger.DisableLog('rdApp.*')
|
||||||
@ -87,6 +89,21 @@ class FormatConverter(object):
|
|||||||
bitvec = MACCSkeys.GenMACCSKeys(mol)
|
bitvec = MACCSkeys.GenMACCSKeys(mol)
|
||||||
return bitvec.ToList()
|
return bitvec.ToList()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_functional_groups(smiles: str) -> List[str]:
|
||||||
|
res = list()
|
||||||
|
|
||||||
|
try:
|
||||||
|
m = Chem.MolFromSmiles(smiles)
|
||||||
|
fgs = ifg.identify_functional_groups(m)
|
||||||
|
for fg in fgs:
|
||||||
|
# TODO atoms or type?
|
||||||
|
res.append(fg.atoms)
|
||||||
|
except AttributeError:
|
||||||
|
logger.debug(f"Could not get functional groups for {smiles}")
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def to_svg(smiles, mol_size=(200, 150), kekulize=True):
|
def to_svg(smiles, mol_size=(200, 150), kekulize=True):
|
||||||
mol = FormatConverter.from_smiles(smiles)
|
mol = FormatConverter.from_smiles(smiles)
|
||||||
@ -131,6 +148,24 @@ class FormatConverter(object):
|
|||||||
# TODO call to AMBIT Service
|
# TODO call to AMBIT Service
|
||||||
return smiles
|
return smiles
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def ep_standardize(smiles):
|
||||||
|
change = True
|
||||||
|
while change:
|
||||||
|
change = False
|
||||||
|
for standardizer in MATCH_STANDARDIZER:
|
||||||
|
tmp_smiles = standardizer.standardize(smiles)
|
||||||
|
|
||||||
|
if tmp_smiles != smiles:
|
||||||
|
print(f"change {smiles} to {tmp_smiles}")
|
||||||
|
change = True
|
||||||
|
smiles = tmp_smiles
|
||||||
|
|
||||||
|
if change is False:
|
||||||
|
print(f"nothing changed")
|
||||||
|
|
||||||
|
return smiles
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def standardize(smiles):
|
def standardize(smiles):
|
||||||
# Taken from https://bitsilla.com/blog/2021/06/standardizing-a-molecule-using-rdkit/
|
# Taken from https://bitsilla.com/blog/2021/06/standardizing-a-molecule-using-rdkit/
|
||||||
@ -180,54 +215,6 @@ class FormatConverter(object):
|
|||||||
atom.UpdatePropertyCache()
|
atom.UpdatePropertyCache()
|
||||||
return mol
|
return mol
|
||||||
|
|
||||||
# @staticmethod
|
|
||||||
# def apply(smiles, smirks, preprocess_smiles=True, bracketize=False, standardize=True):
|
|
||||||
# logger.debug(f'Applying {smirks} on {smiles}')
|
|
||||||
#
|
|
||||||
# if bracketize:
|
|
||||||
# smirks = smirks.split('>>')[0] + ">>(" + smirks.split('>>')[1] + ")"
|
|
||||||
#
|
|
||||||
# res = set()
|
|
||||||
# try:
|
|
||||||
# rxn = rdChemReactions.ReactionFromSmarts(smirks)
|
|
||||||
# mol = Chem.MolFromSmiles(smiles)
|
|
||||||
#
|
|
||||||
# # Inplace
|
|
||||||
# if preprocess_smiles:
|
|
||||||
# Chem.SanitizeMol(mol)
|
|
||||||
# mol = Chem.AddHs(mol)
|
|
||||||
#
|
|
||||||
# # apply!
|
|
||||||
# reacts = rxn.RunReactants((mol,))
|
|
||||||
# if len(reacts):
|
|
||||||
# # Sanitize mols
|
|
||||||
# for product_set in reacts:
|
|
||||||
# prod_set = list()
|
|
||||||
# for product in product_set:
|
|
||||||
# # Fixes
|
|
||||||
# # [2025-01-30 23:00:50] ERROR chem - Sanitizing and converting failed:
|
|
||||||
# # non-ring atom 3 marked aromatic
|
|
||||||
# # But does not improve overall performance
|
|
||||||
# #
|
|
||||||
# # for a in product.GetAtoms():
|
|
||||||
# # if (not a.IsInRing()) and a.GetIsAromatic():
|
|
||||||
# # a.SetIsAromatic(False)
|
|
||||||
# # for b in product.GetBonds():
|
|
||||||
# # if (not b.IsInRing()) and b.GetIsAromatic():
|
|
||||||
# # b.SetIsAromatic(False)
|
|
||||||
#
|
|
||||||
# try:
|
|
||||||
# Chem.SanitizeMol(product)
|
|
||||||
# prod_set.append(FormatConverter.standardize(Chem.MolToSmiles(product)))
|
|
||||||
# except ValueError as e:
|
|
||||||
# logger.error(f'Sanitizing and converting failed:\n{e}')
|
|
||||||
# continue
|
|
||||||
# res.add(tuple(list(set(prod_set))))
|
|
||||||
# except Exception as e:
|
|
||||||
# logger.error(f'Applying {smirks} on {smiles} failed:\n{e}')
|
|
||||||
#
|
|
||||||
# return list(res)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid_smirks(smirks: str) -> bool:
|
def is_valid_smirks(smirks: str) -> bool:
|
||||||
try:
|
try:
|
||||||
@ -237,7 +224,7 @@ class FormatConverter(object):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def apply(smiles: str, smirks: str, preprocess_smiles: bool = True, bracketize: bool = False,
|
def apply(smiles: str, smirks: str, preprocess_smiles: bool = True, bracketize: bool = True,
|
||||||
standardize: bool = True, kekulize: bool = True) -> List['ProductSet']:
|
standardize: bool = True, kekulize: bool = True) -> List['ProductSet']:
|
||||||
logger.debug(f'Applying {smirks} on {smiles}')
|
logger.debug(f'Applying {smirks} on {smiles}')
|
||||||
|
|
||||||
@ -266,8 +253,10 @@ class FormatConverter(object):
|
|||||||
for product in product_set:
|
for product in product_set:
|
||||||
try:
|
try:
|
||||||
Chem.SanitizeMol(product)
|
Chem.SanitizeMol(product)
|
||||||
|
product = GetMolFrags(product, asMols=True)
|
||||||
product = FormatConverter.standardize(Chem.MolToSmiles(product))
|
for p in product:
|
||||||
|
p = FormatConverter.standardize(Chem.MolToSmiles(p))
|
||||||
|
prods.append(p)
|
||||||
|
|
||||||
# if kekulize:
|
# if kekulize:
|
||||||
# # from rdkit.Chem import MolStandardize
|
# # from rdkit.Chem import MolStandardize
|
||||||
@ -292,13 +281,12 @@ class FormatConverter(object):
|
|||||||
# # bond.SetIsAromatic(False)
|
# # bond.SetIsAromatic(False)
|
||||||
# Chem.Kekulize(product)
|
# Chem.Kekulize(product)
|
||||||
|
|
||||||
prods.append(product)
|
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
logger.error(f'Sanitizing and converting failed:\n{e}')
|
logger.error(f'Sanitizing and converting failed:\n{e}')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# TODO doc!
|
if len(prods):
|
||||||
if len(prods) and len(prods) == len(product_set):
|
|
||||||
ps = ProductSet(prods)
|
ps = ProductSet(prods)
|
||||||
pss.add(ps)
|
pss.add(ps)
|
||||||
|
|
||||||
@ -651,7 +639,7 @@ class IndigoUtils(object):
|
|||||||
environment.add(mappedAtom.index())
|
environment.add(mappedAtom.index())
|
||||||
|
|
||||||
for k, v in functional_groups.items():
|
for k, v in functional_groups.items():
|
||||||
|
try:
|
||||||
sanitized = IndigoUtils.sanitize_functional_group(k)
|
sanitized = IndigoUtils.sanitize_functional_group(k)
|
||||||
|
|
||||||
query = indigo.loadSmarts(sanitized)
|
query = indigo.loadSmarts(sanitized)
|
||||||
@ -666,6 +654,9 @@ class IndigoUtils(object):
|
|||||||
|
|
||||||
counts[mappedAtom.index()] = max(v, counts[mappedAtom.index()])
|
counts[mappedAtom.index()] = max(v, counts[mappedAtom.index()])
|
||||||
|
|
||||||
|
except IndigoException as e:
|
||||||
|
logger.debug(f'Colorizing failed due to {e}')
|
||||||
|
|
||||||
for k, v in counts.items():
|
for k, v in counts.items():
|
||||||
if is_reaction:
|
if is_reaction:
|
||||||
color = "128, 0, 128"
|
color = "128, 0, 128"
|
||||||
|
|||||||
524
utilities/ml.py
524
utilities/ml.py
@ -1,46 +1,29 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import dataclasses
|
import logging
|
||||||
|
from abc import ABC, abstractmethod
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import List, Optional
|
from typing import List, Dict, Set, Tuple
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from sklearn.base import BaseEstimator, ClassifierMixin
|
from sklearn.base import BaseEstimator, ClassifierMixin
|
||||||
from sklearn.decomposition import PCA
|
from sklearn.decomposition import PCA
|
||||||
|
from sklearn.ensemble import RandomForestClassifier
|
||||||
from sklearn.metrics import accuracy_score
|
from sklearn.metrics import accuracy_score
|
||||||
from sklearn.multioutput import ClassifierChain
|
from sklearn.multioutput import ClassifierChain
|
||||||
from sklearn.preprocessing import StandardScaler
|
from sklearn.preprocessing import StandardScaler
|
||||||
from sklearn.tree import DecisionTreeClassifier
|
|
||||||
from sklearn.ensemble import RandomForestClassifier
|
|
||||||
|
|
||||||
# @dataclasses.dataclass
|
logger = logging.getLogger(__name__)
|
||||||
# class Feature:
|
|
||||||
# name: str
|
|
||||||
# value: float
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class Row:
|
|
||||||
# def __init__(self, compound_uuid: str, compound_smiles: str, descriptors: List[int]):
|
|
||||||
# self.data = {}
|
|
||||||
#
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# class DataSet(object):
|
|
||||||
#
|
|
||||||
# def __init__(self):
|
|
||||||
# self.rows: List[Row] = []
|
|
||||||
#
|
|
||||||
# def add_row(self, row: Row):
|
|
||||||
# pass
|
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from utilities.chem import FormatConverter
|
from utilities.chem import FormatConverter, PredictionResult
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Compound:
|
class SCompound:
|
||||||
smiles: str
|
smiles: str
|
||||||
uuid: str = field(default=None, compare=False, hash=False)
|
uuid: str = field(default=None, compare=False, hash=False)
|
||||||
|
|
||||||
@ -53,10 +36,10 @@ class Compound:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Reaction:
|
class SReaction:
|
||||||
educts: List[Compound]
|
educts: List[SCompound]
|
||||||
products: List[Compound]
|
products: List[SCompound]
|
||||||
rule_uuid: str = field(default=None, compare=False, hash=False)
|
rule_uuid: SRule = field(default=None, compare=False, hash=False)
|
||||||
reaction_uuid: str = field(default=None, compare=False, hash=False)
|
reaction_uuid: str = field(default=None, compare=False, hash=False)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
@ -68,7 +51,7 @@ class Reaction:
|
|||||||
return self._hash
|
return self._hash
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if not isinstance(other, Reaction):
|
if not isinstance(other, SReaction):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return (
|
return (
|
||||||
sorted(self.educts, key=lambda x: x.smiles) == sorted(other.educts, key=lambda x: x.smiles) and
|
sorted(self.educts, key=lambda x: x.smiles) == sorted(other.educts, key=lambda x: x.smiles) and
|
||||||
@ -76,69 +59,296 @@ class Reaction:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Dataset(object):
|
@dataclass
|
||||||
|
class SRule(ABC):
|
||||||
|
|
||||||
def __init__(self, headers=List['str'], data=List[List[str|int|float]]):
|
@abstractmethod
|
||||||
self.headers = headers
|
def apply(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SSimpleRule:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SParallelRule:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Dataset:
|
||||||
|
|
||||||
|
def __init__(self, columns: List[str], num_labels: int, data: List[List[str | int | float]] = None):
|
||||||
|
self.columns: List[str] = columns
|
||||||
|
self.num_labels: int = num_labels
|
||||||
|
|
||||||
|
if data is None:
|
||||||
|
self.data: List[List[str | int | float]] = list()
|
||||||
|
else:
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
|
self.num_features: int = len(columns) - self.num_labels
|
||||||
|
self._struct_features: Tuple[int, int] = self._block_indices('feature_')
|
||||||
|
self._triggered: Tuple[int, int] = self._block_indices('trig_')
|
||||||
|
self._observed: Tuple[int, int] = self._block_indices('obs_')
|
||||||
|
|
||||||
def features(self):
|
def _block_indices(self, prefix) -> Tuple[int, int]:
|
||||||
pass
|
indices: List[int] = []
|
||||||
|
for i, feature in enumerate(self.columns):
|
||||||
|
if feature.startswith(prefix):
|
||||||
|
indices.append(i)
|
||||||
|
|
||||||
def labels(self):
|
return min(indices), max(indices)
|
||||||
pass
|
|
||||||
|
|
||||||
def to_json(self):
|
def structure_id(self):
|
||||||
pass
|
return self.data[0][0]
|
||||||
|
|
||||||
def to_csv(self):
|
def add_row(self, row: List[str | int | float]):
|
||||||
pass
|
if len(self.columns) != len(row):
|
||||||
|
raise ValueError(f"Header and Data are not aligned {len(self.columns)} vs. {len(row)}")
|
||||||
|
self.data.append(row)
|
||||||
|
|
||||||
def to_arff(self):
|
def times_triggered(self, rule_uuid) -> int:
|
||||||
pass
|
idx = self.columns.index(f'trig_{rule_uuid}')
|
||||||
|
|
||||||
|
times_triggered = 0
|
||||||
|
for row in self.data:
|
||||||
|
if row[idx] == 1:
|
||||||
|
times_triggered += 1
|
||||||
|
|
||||||
|
return times_triggered
|
||||||
|
|
||||||
|
def struct_features(self) -> Tuple[int, int]:
|
||||||
|
return self._struct_features
|
||||||
|
|
||||||
|
def triggered(self) -> Tuple[int, int]:
|
||||||
|
return self._triggered
|
||||||
|
|
||||||
|
def observed(self) -> Tuple[int, int]:
|
||||||
|
return self._observed
|
||||||
|
|
||||||
|
def at(self, position: int) -> Dataset:
|
||||||
|
return Dataset(self.columns, self.num_labels, [self.data[position]])
|
||||||
|
|
||||||
|
def limit(self, limit: int) -> Dataset:
|
||||||
|
return Dataset(self.columns, self.num_labels, self.data[:limit])
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return (self.at(i) for i, _ in enumerate(self.data))
|
||||||
|
|
||||||
|
|
||||||
|
def classification_dataset(self, structures: List[str | 'CompoundStructure'], applicable_rules: List['Rule']) -> Tuple[Dataset, List[List[PredictionResult]]]:
|
||||||
|
classify_data = []
|
||||||
|
classify_products = []
|
||||||
|
for struct in structures:
|
||||||
|
|
||||||
class DatasetGenerator(object):
|
if isinstance(struct, str):
|
||||||
|
struct_id = None
|
||||||
|
struct_smiles = struct
|
||||||
|
else:
|
||||||
|
struct_id = str(struct.uuid)
|
||||||
|
struct_smiles = struct.smiles
|
||||||
|
|
||||||
|
features = FormatConverter.maccs(struct_smiles)
|
||||||
|
|
||||||
|
trig = []
|
||||||
|
prods = []
|
||||||
|
for rule in applicable_rules:
|
||||||
|
products = rule.apply(struct_smiles)
|
||||||
|
|
||||||
|
if len(products):
|
||||||
|
trig.append(1)
|
||||||
|
prods.append(products)
|
||||||
|
else:
|
||||||
|
trig.append(0)
|
||||||
|
prods.append([])
|
||||||
|
|
||||||
|
classify_data.append([struct_id] + features + trig + ([-1] * len(trig)))
|
||||||
|
classify_products.append(prods)
|
||||||
|
|
||||||
|
return Dataset(columns=self.columns, num_labels=self.num_labels, data=classify_data), classify_products
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_dataset(compounds: List[Compound], reactions: List[Reaction], applicable_rules: 'Rule',
|
def generate_dataset(reactions: List['Reaction'], applicable_rules: List['Rule'], educts_only: bool = True) -> Dataset:
|
||||||
compounds_to_exclude: Optional[Compound] = None, educts_only: bool = False) -> Dataset:
|
_structures = set()
|
||||||
|
|
||||||
rows = []
|
|
||||||
|
|
||||||
if educts_only:
|
|
||||||
compounds = set()
|
|
||||||
for r in reactions:
|
for r in reactions:
|
||||||
for e in r.educts:
|
for e in r.educts.all():
|
||||||
compounds.add(e)
|
_structures.add(e)
|
||||||
compounds = list(compounds)
|
|
||||||
|
|
||||||
total = len(compounds)
|
if not educts_only:
|
||||||
for i, c in enumerate(compounds):
|
for e in r.products:
|
||||||
row = []
|
_structures.add(e)
|
||||||
print(f"{i + 1}/{total} - {c.smiles}")
|
|
||||||
for r in applicable_rules:
|
compounds = sorted(_structures, key=lambda x: x.url)
|
||||||
product_sets = r.rule.apply(c.smiles)
|
|
||||||
|
triggered: Dict[str, Set[str]] = defaultdict(set)
|
||||||
|
observed: Set[str] = set()
|
||||||
|
|
||||||
|
# Apply rules on collected compounds and store tps
|
||||||
|
for i, comp in enumerate(compounds):
|
||||||
|
logger.debug(f"{i + 1}/{len(compounds)}...")
|
||||||
|
|
||||||
|
for rule in applicable_rules:
|
||||||
|
product_sets = rule.apply(comp.smiles)
|
||||||
|
|
||||||
if len(product_sets) == 0:
|
if len(product_sets) == 0:
|
||||||
row.append([])
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
#triggered.add(f"{r.uuid} + {c.uuid}")
|
key = f"{rule.uuid} + {comp.uuid}"
|
||||||
reacts = set()
|
|
||||||
for ps in product_sets:
|
|
||||||
products = []
|
|
||||||
for p in ps:
|
|
||||||
products.append(Compound(FormatConverter.standardize(p)))
|
|
||||||
|
|
||||||
reacts.add(Reaction([c], products, r))
|
if key in triggered:
|
||||||
row.append(list(reacts))
|
logger.info(f"{key} already present. Duplicate reaction?")
|
||||||
|
|
||||||
rows.append(row)
|
for prod_set in product_sets:
|
||||||
|
for smi in prod_set:
|
||||||
|
|
||||||
return rows
|
try:
|
||||||
|
smi = FormatConverter.standardize(smi)
|
||||||
|
except Exception:
|
||||||
|
# :shrug:
|
||||||
|
logger.debug(f'Standardizing SMILES failed for {smi}')
|
||||||
|
pass
|
||||||
|
|
||||||
|
triggered[key].add(smi)
|
||||||
|
|
||||||
|
for i, r in enumerate(reactions):
|
||||||
|
logger.debug(f"{i + 1}/{len(reactions)}...")
|
||||||
|
|
||||||
|
if len(r.educts.all()) != 1:
|
||||||
|
logger.debug(f"Skipping {r.url} as it has {len(r.educts.all())} substrates!")
|
||||||
|
continue
|
||||||
|
|
||||||
|
for comp in r.educts.all():
|
||||||
|
for rule in applicable_rules:
|
||||||
|
key = f"{rule.uuid} + {comp.uuid}"
|
||||||
|
|
||||||
|
if key not in triggered:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# standardize products from reactions for comparison
|
||||||
|
standardized_products = []
|
||||||
|
for cs in r.products.all():
|
||||||
|
smi = cs.smiles
|
||||||
|
|
||||||
|
try:
|
||||||
|
smi = FormatConverter.standardize(smi)
|
||||||
|
except Exception as e:
|
||||||
|
# :shrug:
|
||||||
|
logger.debug(f'Standardizing SMILES failed for {smi}')
|
||||||
|
pass
|
||||||
|
|
||||||
|
standardized_products.append(smi)
|
||||||
|
|
||||||
|
if len(set(standardized_products).difference(triggered[key])) == 0:
|
||||||
|
observed.add(key)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
ds = None
|
||||||
|
|
||||||
|
for i, comp in enumerate(compounds):
|
||||||
|
# Features
|
||||||
|
feat = FormatConverter.maccs(comp.smiles)
|
||||||
|
trig = []
|
||||||
|
obs = []
|
||||||
|
|
||||||
|
for rule in applicable_rules:
|
||||||
|
key = f"{rule.uuid} + {comp.uuid}"
|
||||||
|
|
||||||
|
# Check triggered
|
||||||
|
if key in triggered:
|
||||||
|
trig.append(1)
|
||||||
|
else:
|
||||||
|
trig.append(0)
|
||||||
|
|
||||||
|
# Check obs
|
||||||
|
if key in observed:
|
||||||
|
obs.append(1)
|
||||||
|
elif key not in triggered:
|
||||||
|
obs.append(None)
|
||||||
|
else:
|
||||||
|
obs.append(0)
|
||||||
|
|
||||||
|
if ds is None:
|
||||||
|
header = ['structure_id'] + \
|
||||||
|
[f'feature_{i}' for i, _ in enumerate(feat)] \
|
||||||
|
+ [f'trig_{r.uuid}' for r in applicable_rules] \
|
||||||
|
+ [f'obs_{r.uuid}' for r in applicable_rules]
|
||||||
|
ds = Dataset(header, len(applicable_rules))
|
||||||
|
|
||||||
|
ds.add_row([str(comp.uuid)] + feat + trig + obs)
|
||||||
|
|
||||||
|
return ds
|
||||||
|
|
||||||
|
|
||||||
|
def X(self, exclude_id_col=True, na_replacement=0):
|
||||||
|
res = self.__getitem__((slice(None), slice(1 if exclude_id_col else 0, len(self.columns) - self.num_labels)))
|
||||||
|
if na_replacement is not None:
|
||||||
|
res = [[x if x is not None else na_replacement for x in row] for row in res]
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def y(self, na_replacement=0):
|
||||||
|
res = self.__getitem__((slice(None), slice(len(self.columns) - self.num_labels, None)))
|
||||||
|
if na_replacement is not None:
|
||||||
|
res = [[x if x is not None else na_replacement for x in row] for row in res]
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if not isinstance(key, tuple):
|
||||||
|
raise TypeError("Dataset must be indexed with dataset[rows, columns]")
|
||||||
|
|
||||||
|
row_key, col_key = key
|
||||||
|
|
||||||
|
# Normalize rows
|
||||||
|
if isinstance(row_key, int):
|
||||||
|
rows = [self.data[row_key]]
|
||||||
|
else:
|
||||||
|
rows = self.data[row_key]
|
||||||
|
|
||||||
|
# Normalize columns
|
||||||
|
if isinstance(col_key, int):
|
||||||
|
res = [row[col_key] for row in rows]
|
||||||
|
else:
|
||||||
|
res = [[row[i] for i in range(*col_key.indices(len(row)))] if isinstance(col_key, slice)
|
||||||
|
else [row[i] for i in col_key] for row in rows]
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
def save(self, path: 'Path'):
|
||||||
|
import pickle
|
||||||
|
with open(path, "wb") as fh:
|
||||||
|
pickle.dump(self, fh)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load(path: 'Path'):
|
||||||
|
import pickle
|
||||||
|
return pickle.load(open(path, "rb"))
|
||||||
|
|
||||||
|
def to_arff(self, path: 'Path'):
|
||||||
|
arff = f"@relation 'enviPy-dataset: -C {self.num_labels}'\n"
|
||||||
|
arff += "\n"
|
||||||
|
for c in self.columns[-self.num_labels:] + self.columns[:self.num_features]:
|
||||||
|
if c == 'structure_id':
|
||||||
|
arff += f"@attribute {c} string\n"
|
||||||
|
else:
|
||||||
|
arff += f"@attribute {c} {{0,1}}\n"
|
||||||
|
|
||||||
|
arff += f"\n@data\n"
|
||||||
|
for d in self.data:
|
||||||
|
ys = ','.join([str(v if v is not None else '?') for v in d[-self.num_labels:]])
|
||||||
|
xs = ','.join([str(v if v is not None else '?') for v in d[:self.num_features]])
|
||||||
|
arff += f'{ys},{xs}\n'
|
||||||
|
|
||||||
|
with open(path, "w") as fh:
|
||||||
|
fh.write(arff)
|
||||||
|
fh.flush()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<Dataset #rows={len(self.data)} #cols={len(self.columns)} #labels={self.num_labels}>"
|
||||||
|
|
||||||
|
|
||||||
class SparseLabelECC(BaseEstimator, ClassifierMixin):
|
class SparseLabelECC(BaseEstimator, ClassifierMixin):
|
||||||
@ -166,8 +376,7 @@ class SparseLabelECC(BaseEstimator, ClassifierMixin):
|
|||||||
self.keep_columns_.append(col)
|
self.keep_columns_.append(col)
|
||||||
|
|
||||||
y_reduced = y[:, self.keep_columns_]
|
y_reduced = y[:, self.keep_columns_]
|
||||||
self.chains_ = [ClassifierChain(self.base_clf, order='random', random_state=i)
|
self.chains_ = [ClassifierChain(self.base_clf) for i in range(self.num_chains)]
|
||||||
for i in range(self.num_chains)]
|
|
||||||
|
|
||||||
for i, chain in enumerate(self.chains_):
|
for i, chain in enumerate(self.chains_):
|
||||||
print(f"{datetime.now()} fitting {i + 1}/{self.num_chains}")
|
print(f"{datetime.now()} fitting {i + 1}/{self.num_chains}")
|
||||||
@ -208,26 +417,169 @@ class SparseLabelECC(BaseEstimator, ClassifierMixin):
|
|||||||
return accuracy_score(y_true, y_pred, sample_weight=sample_weight)
|
return accuracy_score(y_true, y_pred, sample_weight=sample_weight)
|
||||||
|
|
||||||
|
|
||||||
class ApplicabilityDomain(PCA):
|
|
||||||
|
|
||||||
def __init__(self, n_components=5):
|
import copy
|
||||||
super().__init__(n_components=n_components)
|
|
||||||
|
import numpy as np
|
||||||
|
from sklearn.dummy import DummyClassifier
|
||||||
|
from sklearn.tree import DecisionTreeClassifier
|
||||||
|
|
||||||
|
|
||||||
|
class BinaryRelevance:
|
||||||
|
def __init__(self, baseline_clf):
|
||||||
|
self.clf = baseline_clf
|
||||||
|
self.classifiers = None
|
||||||
|
|
||||||
|
def fit(self, X, Y):
|
||||||
|
if self.classifiers is None:
|
||||||
|
self.classifiers = []
|
||||||
|
|
||||||
|
for l in range(len(Y[0])):
|
||||||
|
X_l = X[~np.isnan(Y[:, l])]
|
||||||
|
Y_l = (Y[~np.isnan(Y[:, l]), l])
|
||||||
|
if len(X_l) == 0: # all labels are nan -> predict 0
|
||||||
|
clf = DummyClassifier(strategy='constant', constant=0)
|
||||||
|
clf.fit([X[0]], [0])
|
||||||
|
self.classifiers.append(clf)
|
||||||
|
continue
|
||||||
|
elif len(np.unique(Y_l)) == 1: # only one class -> predict that class
|
||||||
|
clf = DummyClassifier(strategy='most_frequent')
|
||||||
|
else:
|
||||||
|
clf = copy.deepcopy(self.clf)
|
||||||
|
clf.fit(X_l, Y_l)
|
||||||
|
self.classifiers.append(clf)
|
||||||
|
|
||||||
|
def predict(self, X):
|
||||||
|
labels = []
|
||||||
|
for clf in self.classifiers:
|
||||||
|
labels.append(clf.predict(X))
|
||||||
|
return np.column_stack(labels)
|
||||||
|
|
||||||
|
def predict_proba(self, X):
|
||||||
|
labels = np.empty((len(X), 0))
|
||||||
|
for clf in self.classifiers:
|
||||||
|
pred = clf.predict_proba(X)
|
||||||
|
if pred.shape[1] > 1:
|
||||||
|
pred = pred[:, 1]
|
||||||
|
else:
|
||||||
|
pred = pred * clf.predict([X[0]])[0]
|
||||||
|
labels = np.column_stack((labels, pred))
|
||||||
|
return labels
|
||||||
|
|
||||||
|
|
||||||
|
class MissingValuesClassifierChain:
|
||||||
|
def __init__(self, base_clf):
|
||||||
|
self.base_clf = base_clf
|
||||||
|
self.permutation = None
|
||||||
|
self.classifiers = None
|
||||||
|
|
||||||
|
def fit(self, X, Y):
|
||||||
|
X = np.array(X)
|
||||||
|
Y = np.array(Y)
|
||||||
|
if self.permutation is None:
|
||||||
|
self.permutation = np.random.permutation(len(Y[0]))
|
||||||
|
|
||||||
|
Y = Y[:, self.permutation]
|
||||||
|
|
||||||
|
if self.classifiers is None:
|
||||||
|
self.classifiers = []
|
||||||
|
|
||||||
|
for p in range(len(self.permutation)):
|
||||||
|
X_p = X[~np.isnan(Y[:, p])]
|
||||||
|
Y_p = Y[~np.isnan(Y[:, p]), p]
|
||||||
|
if len(X_p) == 0: # all labels are nan -> predict 0
|
||||||
|
clf = DummyClassifier(strategy='constant', constant=0)
|
||||||
|
self.classifiers.append(clf.fit([X[0]], [0]))
|
||||||
|
elif len(np.unique(Y_p)) == 1: # only one class -> predict that class
|
||||||
|
clf = DummyClassifier(strategy='most_frequent')
|
||||||
|
self.classifiers.append(clf.fit(X_p, Y_p))
|
||||||
|
else:
|
||||||
|
clf = copy.deepcopy(self.base_clf)
|
||||||
|
self.classifiers.append(clf.fit(X_p, Y_p))
|
||||||
|
newcol = Y[:, p]
|
||||||
|
pred = clf.predict(X)
|
||||||
|
newcol[np.isnan(newcol)] = pred[np.isnan(newcol)] # fill in missing values with clf predictions
|
||||||
|
X = np.column_stack((X, newcol))
|
||||||
|
|
||||||
|
def predict(self, X):
|
||||||
|
labels = np.empty((len(X), 0))
|
||||||
|
for clf in self.classifiers:
|
||||||
|
pred = clf.predict(np.column_stack((X, labels)))
|
||||||
|
labels = np.column_stack((labels, pred))
|
||||||
|
return labels[:, np.argsort(self.permutation)]
|
||||||
|
|
||||||
|
def predict_proba(self, X):
|
||||||
|
labels = np.empty((len(X), 0))
|
||||||
|
for clf in self.classifiers:
|
||||||
|
pred = clf.predict_proba(np.column_stack((X, np.round(labels))))
|
||||||
|
if pred.shape[1] > 1:
|
||||||
|
pred = pred[:, 1]
|
||||||
|
else:
|
||||||
|
pred = pred * clf.predict(np.column_stack(([X[0]], np.round([labels[0]]))))[0]
|
||||||
|
labels = np.column_stack((labels, pred))
|
||||||
|
return labels[:, np.argsort(self.permutation)]
|
||||||
|
|
||||||
|
|
||||||
|
class EnsembleClassifierChain:
|
||||||
|
def __init__(self, base_clf, num_chains=10):
|
||||||
|
self.base_clf = base_clf
|
||||||
|
self.num_chains = num_chains
|
||||||
|
self.num_labels = None
|
||||||
|
self.classifiers = None
|
||||||
|
|
||||||
|
def fit(self, X, Y):
|
||||||
|
if self.classifiers is None:
|
||||||
|
self.classifiers = []
|
||||||
|
|
||||||
|
if self.num_labels is None:
|
||||||
|
self.num_labels = len(Y[0])
|
||||||
|
|
||||||
|
for p in range(self.num_chains):
|
||||||
|
print(f"{datetime.now()} fitting {p + 1}/{self.num_chains}")
|
||||||
|
clf = MissingValuesClassifierChain(self.base_clf)
|
||||||
|
clf.fit(X, Y)
|
||||||
|
self.classifiers.append(clf)
|
||||||
|
|
||||||
|
def predict(self, X):
|
||||||
|
labels = np.zeros((len(X), self.num_labels))
|
||||||
|
for clf in self.classifiers:
|
||||||
|
labels += clf.predict(X)
|
||||||
|
return np.round(labels / self.num_chains)
|
||||||
|
|
||||||
|
def predict_proba(self, X):
|
||||||
|
labels = np.zeros((len(X), self.num_labels))
|
||||||
|
for clf in self.classifiers:
|
||||||
|
labels += clf.predict_proba(X)
|
||||||
|
return labels / self.num_chains
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ApplicabilityDomainPCA(PCA):
|
||||||
|
|
||||||
|
def __init__(self, num_neighbours: int = 5):
|
||||||
|
super().__init__(n_components=num_neighbours)
|
||||||
self.scaler = StandardScaler()
|
self.scaler = StandardScaler()
|
||||||
|
self.num_neighbours = num_neighbours
|
||||||
self.min_vals = None
|
self.min_vals = None
|
||||||
self.max_vals = None
|
self.max_vals = None
|
||||||
|
|
||||||
def build(self, X):
|
def build(self, train_dataset: 'Dataset'):
|
||||||
# transform
|
# transform
|
||||||
X_scaled = self.scaler.fit_transform(X)
|
X_scaled = self.scaler.fit_transform(train_dataset.X())
|
||||||
# fit pca
|
# fit pca
|
||||||
X_pca = self.fit_transform(X_scaled)
|
X_pca = self.fit_transform(X_scaled)
|
||||||
|
|
||||||
self.max_vals = np.max(X_pca, axis=0)
|
self.max_vals = np.max(X_pca, axis=0)
|
||||||
self.min_vals = np.min(X_pca, axis=0)
|
self.min_vals = np.min(X_pca, axis=0)
|
||||||
|
|
||||||
def is_applicable(self, instances):
|
def __transform(self, instances):
|
||||||
instances_scaled = self.scaler.transform(instances)
|
instances_scaled = self.scaler.transform(instances)
|
||||||
instances_pca = self.transform(instances_scaled)
|
instances_pca = self.transform(instances_scaled)
|
||||||
|
return instances_pca
|
||||||
|
|
||||||
|
def is_applicable(self, classify_instances: 'Dataset'):
|
||||||
|
instances_pca = self.__transform(classify_instances.X())
|
||||||
|
|
||||||
is_applicable = []
|
is_applicable = []
|
||||||
for i, instance in enumerate(instances_pca):
|
for i, instance in enumerate(instances_pca):
|
||||||
@ -237,3 +589,17 @@ class ApplicabilityDomain(PCA):
|
|||||||
is_applicable[i] = False
|
is_applicable[i] = False
|
||||||
|
|
||||||
return is_applicable
|
return is_applicable
|
||||||
|
|
||||||
|
|
||||||
|
def tanimoto_distance(a: List[int], b: List[int]):
|
||||||
|
if len(a) != len(b):
|
||||||
|
raise ValueError(f"Lists must be the same length {len(a)} != {len(b)}")
|
||||||
|
|
||||||
|
sum_a = sum(a)
|
||||||
|
sum_b = sum(b)
|
||||||
|
sum_c = sum(v1 and v2 for v1, v2 in zip(a, b))
|
||||||
|
|
||||||
|
if sum_a + sum_b - sum_c == 0:
|
||||||
|
return 0.0
|
||||||
|
|
||||||
|
return 1 - (sum_c / (sum_a + sum_b - sum_c))
|
||||||
|
|||||||
Reference in New Issue
Block a user