Commit 2bd6a9b1 authored by Hervé  MENAGER's avatar Hervé MENAGER
Browse files

Merge branch 'master' into 'release'

Prepare for v1.0.3

See merge request !20
parents 24b5d5bf e231ff32
Pipeline #42116 canceled with stages
......@@ -54,7 +54,8 @@ extensions = [
'sphinx.ext.intersphinx',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'sphinx.ext.graphviz'
'sphinx.ext.graphviz',
'sphinxcontrib.bibtex'
]
# Add any paths that contain templates here, relative to this directory.
......
......@@ -18,6 +18,7 @@ These pages contain the documentation for technical maintenance and development
install
configuration
database
webservices
modules
......
This diff is collapsed.
......@@ -8,6 +8,7 @@ import operator
import re
import sys
from boltons.iterutils import flatten, unique_iter
from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
......@@ -985,6 +986,20 @@ class Compound(AutoFillableModel):
.count()
)
@property
def pk_tests_count(self):
"""
Return the number of associated pharmacokinetic tests
"""
return self.compoundpkresult_set.all().count()
@property
def cytotoxicity_tests_count(self):
"""
Return the number of associated cytotoxicity tests
"""
return self.compoundcytotoxicityresult_set.all().count()
@property
def sorted_similar_drugbank_compounds(self):
"""
......@@ -1183,6 +1198,60 @@ class Compound(AutoFillableModel):
CompoundTanimoto.objects.filter(compound=self).delete()
DrugbankCompoundTanimoto.objects.filter(compound=self).delete()
def get_target_activities_table(self):
"""
Return test activity result data as a list of
items containing for each PPI family the compound
was tested against, the best activity, the linked diseases
and the modulation types
"""
ppi_families = [
item["test_activity_description__ppi__family"]
for item in self.compoundactivityresult_set.filter(
~Q(activity_type="KdRat")
)
.order_by()
.values("test_activity_description__ppi__family")
.distinct()
]
results = []
for ppi_family in ppi_families:
family_compound_activity_results = self.compoundactivityresult_set.filter(
~Q(activity_type="KdRat")
).filter(test_activity_description__ppi__family__id=ppi_family)
best_activity = (
family_compound_activity_results.order_by("-activity")
.values("activity")
.first()["activity"]
)
diseases = list(
unique_iter(
flatten(
[
list(fcar.test_activity_description.ppi.diseases.all())
for fcar in family_compound_activity_results
]
)
)
)
modulation_types = list(
set(
[
fcar.get_modulation_type_display()
for fcar in family_compound_activity_results
]
)
)
results.append(
{
"family": PpiFamily.objects.get(id=ppi_family),
"best_activity": best_activity,
"diseases": diseases,
"modulation_types": modulation_types,
}
)
return results
class CompoundTanimoto(models.Model):
canonical_smiles = models.TextField("Canonical Smile")
......@@ -1867,9 +1936,9 @@ def update_compound_cached_properties(compounds_queryset=None):
)
.values("_bindtest_av")[:1]
),
pktest_av=Exists(CompoundPKResult.objects.filter(id=OuterRef("id"))),
pktest_av=Exists(CompoundPKResult.objects.filter(compound__id=OuterRef("id"))),
cytoxtest_av=Exists(
CompoundCytotoxicityResult.objects.filter(id=OuterRef("id"))
CompoundCytotoxicityResult.objects.filter(compound__id=OuterRef("id"))
),
insilico_av=Subquery(
compounds_queryset.filter(id=OuterRef("id"))
......
......@@ -55,7 +55,7 @@
<div class="row" style="display: inline-block;height:auto; margin-right: 15px; margin-left: 15px;">
<div class="tab-content" id="tabContent">
<div class="tab-pane fade show active" id="compound" role="tabpanel" aria-labelledby="compound-tab">
<div class="card">
<div class="card inner-wrap">
<div class="card-body">
{% include "compound_l_item.html" with compound=compound show_detail=True %}
</div>
......@@ -382,20 +382,7 @@
<div class="row d-flex justify-content-center">
<div class="col-sm-12 col-md-9" style="margin: 10px;">
<h5 class="card_title">Summary</h5>
<div class="card_border row" style="text-align: center;">
<div class="col-md-4">
<h6 class="card_title">Bibliographic ressources</h6>
<p>{{ compound.biblio_refs.count }}</p>
</div>
<div class="col-md-4">
<h6 class="card_title">Biochemical tests</h6>
<p>{{ compound.bioch_tests_count }}</p>
</div>
<div class="col-md-4">
<h6 class="card_title">Cellular tests</h6>
<p>{{ compound.cell_tests_count }}</p>
</div>
</div>
{% include "compound_test_counts.html" with compound=compound show_bibrefs=True %}
</div>
</div>
<div class="row d-flex justify-content-center">
......
{%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id or compound.ligand_id %}
<table class="table mb-0">
<table class="table m-1 card_border">
<tbody>
<tr class="row">
<tr class="table-row">
<td scope="col" class="col-2 text-center">
{% if compound.pubchem_id %}
<a href="{{ compound.pubchem_url }}" target="_blank"><img
......
<table class="table mb-0">
<table class="table m-1 card_border">
<tbody>
<tr class="row">
<tr class="table-row">
<td scope="col" class="col-2 text-center">
<a href="https://www.ncbi.nlm.nih.gov/pccompound?term={{ compound.inchikey }}" target="_blank"><img src="/static/images/Other/Pubchemlogo.png" style="height: 1.5em;" title="search INCHIKEY on PubChem" /></a>
</td>
......
{% load customtags %}
<div class="row m-2 border border-info bg-light border_card" style="box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.2);">
{%if show_detail != True %}
<div class="col-sm-3 border-info d-flex justify-content-center align-content-center {% if compound.replaced_with or compound.is_validated is False %}bg_warning{% endif %}">
<a href="/compounds/{{ compound.id }}">{% include "compound_smiles_draw.html" with id=compound.id smile=compound.canonical_smile %}</a>
<div class="col-sm-3 border-info justify-content-center align-content-center {% if compound.replaced_with or compound.is_validated is False %}bg_warning{% endif %}">
<div class="row">
<a style="overflow: hidden;" href="/compounds/{{ compound.id }}">{% include "compound_smiles_draw.html" with id=compound.id smile=compound.canonical_smile %}</a>
<h2 class="position-absolute" style="top:0.3em; left:0.3em;"><span class="badge badge-light"><a href="/compounds/{{ compound.id }}">{{ compound.id }}</a></span>{% if compound.replaced_with is not None %}
<span style="font-size: 26px; color:#fa8005; font-size: 75%;">replaced with <a href="/compounds/{{ compound.replaced_with.id }}">{{ compound.replaced_with.id }}</a></span>{% elif compound.is_validated is False %}<span
style="font-size: 26px; color:#fa8005;">not validated</span>{% endif %}</h2>
......@@ -9,6 +12,26 @@
<h2 class="position-absolute" style="top:0.3em; right:0.3em;" title="tanimoto similarity value"><span class="badge badge-light text-warning">{{ compound.tanimoto }}</span></h2>
{% endif %}
</div>
<h4 class="pt-2 compound_list_title">Chemistry rules</h4>
<div class="row m-1">
<table class="table table-sm col-sm-12 col-md-6 card_border m-1" style="text-align: center;">
<thead>
<tr>
<th scope="col" class="card_title col_width">Lipinski's RO5</th>
<th scope="col" class="card_title col_width">Veber</th>
<th scope="col" class="card_title col_width">Pfizer's 3/75</th>
</tr>
</thead>
<tbody>
<tr>
<td>{% rule_status_icon compound.lipinsky "Lipinski's RO5" %}</td>
<td>{% rule_status_icon compound.veber "Veber" %}</td>
<td>{% rule_status_icon compound.pfizer "Pfizer" %}</td>
</tr>
</tbody>
</table>
</div>
</div>
{% endif %}
<div class="{%if show_detail != True %}col-sm-9{% else %}col-sm-12{% endif %}">
<h4 class="pt-2 compound_list_title">Identifiers</h4>
......@@ -17,16 +40,16 @@
<li class="list-group-item">Common name: {{ compound.common_name }}</li>
{% endif %}
{% if compound.canonical_smile %}
<li class="list-group-item">Canonical SMILES: {{ compound.canonical_smile }}</li>
<li class="list-group-item">Canonical SMILES: <pre style="overflow: scroll;">{{ compound.canonical_smile }}</pre></li>
{% endif %}
{% if compound.iupac_name %}
<li class="list-group-item">IUPAC name: {{ compound.iupac_name }}</li>
<li class="list-group-item">IUPAC name: <pre style="overflow: scroll;">{{ compound.iupac_name }}</pre></li>
{% endif %}
{% if compound.inchi %}
<li class="list-group-item">InChi: {{ compound.inchi }}</li>
<li class="list-group-item">InChi: <pre style="overflow: scroll;">{{ compound.inchi }}</pre></li>
{% endif %}
{% if compound.inchikey %}
<li class="list-group-item">InChiKey: {{ compound.inchikey }}</li>
<li class="list-group-item">InChiKey: <pre style="overflow: scroll;">{{ compound.inchikey }}</pre></li>
{% endif %}
</ul>
{%if compound.pubchem_id or compound.chembl_id or compound.chemspider_id or compound.ligand_id %}
......@@ -38,24 +61,56 @@
{% include "compound_dbsearch_links.html" %}
{% endif %}
{% if compound.biblio_refs %}
<h4 class="pt-2 compound_list_title">Bibliography</h4>
<table class="table">
<h4 class="pt-2 compound_list_title">Bibliography ({{compound.biblio_refs.count}})</h4>
<table class="table m-1 card_border">
<thead>
<tr>
<tr class="table-row">
<th scope="col">Publication</th>
<th scope="col" title="Compound name in publication">Name</th>
</tr>
</thead>
<tbody>
{% for biblio_ref in compound.biblio_refs %}
<tr>
<tr class="table-row">
<td scope="col">{% include "biblio_citation.html" with bibliography=biblio_ref.bibliography%}</td>
<td scope="col">{{ biblio_ref.compound_name }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</ul>
<h4 class="pt-2 compound_list_title">Pharmacological data</h4>
{% include "compound_test_counts.html" with compound=compound show_bibrefs=False %}
<h4 class="pt-2 compound_list_title">Targets</h4>
<table class="table m-1 card_border">
<thead>
<tr class="table-row">
<th scope="col">PPI family</th>
<th scope="col">Best activity</th>
<th scope="col">Diseases</th>
<th scope="col" title="Molecular Mechanism of Action">MMoA</th>
</tr>
</thead>
<tbody>
{% for row in compound.get_target_activities_table %}
<tr class="table-row">
<td scope="col">{{ row.family.name }}</td>
<td scope="col">{{ row.best_activity|floatformat:2 }}</td>
<td scope="col">
{% for disease in row.diseases %}
{{ disease.name }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
</td>
<td scope="col">
{% for modulation_type in row.modulation_types %}
{{ modulation_type }}
{% if not forloop.last %}, {% endif %}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
</div>
......@@ -29,7 +29,7 @@
</div>
<div class="inner-wrap container-fluid ">
<div class="row flex-xl-nowrap">
<div class="row">
<main class="col-12" role="main">
<h1 class="page-title">Query compounds</h1>
......
<table class="table m-1 card_border">
<thead>
<tr class="table-row">
{% if show_bibrefs %}
<th scope="col">Bibliographic ressources</th>
{% endif %}
<th scope="col" title="Biochemical tests">Biochemical tests</th>
<th scope="col" title="Cellular tests">Cellular tests</th>
<th scope="col" title="Pharmacokinetic tests">PK tests</th>
<th scope="col" title="Cytotoxicity tests">Cytotoxicity tests</th>
</tr>
</thead>
<tbody>
<tr class="table-row">
{% if show_bibrefs %}
<td scope="col">{{ compound.biblio_refs.count }}</td>
{% endif %}
<th scope="col" title="Biochemical tests">{{ compound.bioch_tests_count }}</th>
<th scope="col" title="Cellular tests">{{ compound.cell_tests_count }}</th>
<th scope="col" title="Pharmacokinetic tests">{{ compound.pk_tests_count }}</th>
<th scope="col" title="Cytotoxicity tests">{{ compound.cytotoxicity_tests_count }}</th>
</tr>
</tbody>
</table>
\ No newline at end of file
......@@ -29,6 +29,22 @@ def status_class(value):
return "table-secondary"
@register.simple_tag
def rule_status_icon(value, title):
if value is True:
class_suffix = "success"
icon_suffix = "check"
elif value is False:
class_suffix = "danger"
icon_suffix = "times"
else:
class_suffix = "secondary"
class_suffix = "question"
return mark_safe(
f'<i class="fas fa-{icon_suffix} text-{class_suffix}" title="{title}: failed"></i>'
)
@register.filter
def bootstrap(object):
return mark_safe("".join(bootstrap_core(object)))
......@@ -88,7 +104,11 @@ def bootstrap_core(object):
css_classes.add("formset-item-delete")
# HACK: if the css_class is a bootstrap column layout, transfer it to container element
for css_class in css_classes:
if css_class.startswith("col") or css_class.startswith("order-") or css_class.startswith("mb-"):
if (
css_class.startswith("col")
or css_class.startswith("order-")
or css_class.startswith("mb-")
):
wrapping_classes += f" {css_class}"
css_classes = set(
[
......
......@@ -29,3 +29,4 @@ git+https://gitlab.pasteur.fr/hmenager/django-diu.git#egg=django_diu
django-crispy-forms
celery==4.4.7
django-polymorphic
boltons
......@@ -6,6 +6,7 @@ flake8-black
# documentation generation
sphinx
sphinx_rtd_theme
sphinxcontrib-bibtex
# coverage
coverage
# tests
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment