Commit a0e6a5a5 authored by Hervé  MENAGER's avatar Hervé MENAGER
Browse files

Merge branch 'master' into 'release'

Prepare v1.0.1

See merge request !17
parents b3f7f4b9 c7980e01
Pipeline #38317 failed with stages
in 5 minutes and 54 seconds
......@@ -172,20 +172,6 @@ class IdForm(forms.Form):
.first()
)
# def get_or_create(self):
# b = models.Bibliography.objects \
# .filter(id_source=self.cleaned_data["id_source"]).filter(source=self.cleaned_data["source"]) \
# .annotate(used=Count("refcompoundbiblio")) \
# .filter(used=0) \
# .first()
# if b is not None:
# return b, False
# else:
# return models.Bibliography.objects.create(
# source=self.cleaned_data["source"],
# id_source=self.cleaned_data["id_source"],
# ), True
""" Step 2 : BibliographyForm """
......@@ -424,10 +410,6 @@ class ComplexCompositionBaseFormSet(forms.BaseFormSet):
if form.cleaned_data.get("DELETE", False):
continue
complex_type_dict.add(form.cleaned_data.get("complex_type"))
if self.has_bound and self.has_partner and len(complex_type_dict) < 2:
self._non_form_errors.append(
_("You need at least one bound and one partner")
)
def __init__(
self,
......@@ -482,7 +464,7 @@ class PpiModelForm(ModelForm):
"data-olsontology": "mondo",
"data-selectpath": "https://www.ebi.ac.uk/ols/",
"olstype": "",
"class": ""
"class": "",
}
),
)
......@@ -492,12 +474,6 @@ class PpiModelForm(ModelForm):
required=False,
)
# other_diseases = forms.CharField(
# label=_("other_diseases_label"),
# help_text=_("other_diseases_help_text"),
# required=False,
# )
class Meta:
model = models.Ppi
fields = (
......@@ -509,7 +485,6 @@ class PpiModelForm(ModelForm):
"pockets_nb", # pockets_nb is Ppi.pockets_nb in the xlsx file of #33
"ols_diseases",
"selected_diseases",
# 'other_diseases',
)
widgets = {
"id": forms.HiddenInput(),
......@@ -536,17 +511,6 @@ class PpiModelForm(ModelForm):
self.fields["symmetry"].initial = symmetry.first()
self.fields["symmetry"].widget = forms.HiddenInput()
pdb_id = initial.get("pdb_id", None)
if pdb_id is not None:
# FIXME move PFAM choice to relevant form ;)
pfams = ws.get_pdb_pfam_mapping(pdb_id) # noqa: F841
# choices = self.fields["family_name"].choices
# for key, values in pfams.items():
# text = "{} ({})".format(values["name"], key)
# choices.append((text, text))
# self.fields["family_name"].choices = choices
# self.fields["family_name"].initial = choices[-1][0]
def full_clean(self):
super().full_clean()
if hasattr(self, "cleaned_data") and "family_name" in self.cleaned_data:
......@@ -574,13 +538,6 @@ class PpiModelForm(ModelForm):
name=name, identifier=identifier
)
self.instance.diseases.add(disease)
# for new_disease in self.cleaned_data['other_diseases'].split(','):
# new_disease = new_disease.strip()
# if len(new_disease) == 0:
# continue
# print(new_disease)
# disease, created = Disease.objects.get_or_create(name=new_disease)
# self.instance.diseases.add(disease)
self.instance.family = models.PpiFamily.objects.get(
id=self.cleaned_data["family"]
)
......@@ -1052,7 +1009,7 @@ CompoundActivityResultInlineFormset = inlineformset_factory(
class TestActivityDescriptionForm(forms.ModelForm):
test_name = CharFieldDataList(
data_class=models.TestActivityDescription, data_attr="test_name"
data_class=models.TestActivityDescription, data_attr="test_name",
)
cell_line_name = CharFieldDataList(
......@@ -1077,6 +1034,11 @@ class TestActivityDescriptionForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["test_type"].widget.attrs["onchange"] = "test_type_changed(this);"
self.fields["test_type"].widget.attrs.update({"class": "col-2"})
self.fields["test_name"].widget.attrs.update({"class": "col-9"})
self.fields["test_modulation_type"].widget.attrs.update({"class": "col-2"})
self.fields["nb_active_compounds"].widget.attrs.update({"class": "col-3"})
self.fields["cell_line_name"].widget.attrs.update({"class": "col-6"})
def has_changed(self):
"""
......
......@@ -3,13 +3,13 @@
from django.db import migrations, models
import django.db.models.deletion
from ippidb.models import Compound, DrugBankCompound
def run_generate_drugbank_inchikey(apps, schema_editor):
DrugBankCompound = apps.get_model("ippidb", "DrugBankCompound")
for drugbank_compound in DrugBankCompound.objects.all():
drugbank_compound.save(autofill=True)
def set_compound_drugbank_links(apps, schema_editor):
Compound = apps.get_model("ippidb", "Compound")
for compound in Compound.objects.all():
compound.set_drugbank_link()
compound.save()
......
# Generated by Django 2.2.1 on 2020-09-14 18:02
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('ippidb', '0064_proteindomaincomplex_polymorphic_ctype'),
]
operations = [
migrations.AddField(
model_name='compound',
name='replaced_with',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ippidb.Compound', verbose_name='Replacement ID'),
),
]
......@@ -570,11 +570,13 @@ class CompoundsManager(models.Manager):
qs = self.get_queryset()
if current_user.is_anonymous:
qs = qs.exclude(compoundaction__ppi__contribution__validated=False)
qs = qs.filter(replaced_with__isnull=True)
elif not current_user.is_superuser:
qs = qs.exclude(
Q(compoundaction__ppi__contribution__validated=False),
~Q(compoundaction__ppi__contribution__contributor=current_user),
)
qs = qs.filter(replaced_with__isnull=True)
return qs
def validated(self):
......@@ -865,6 +867,14 @@ class Compound(AutoFillableModel):
verbose_name="Number of tests available", null=True, blank=True
)
replaced_with = models.ForeignKey(
"self",
verbose_name="Replacement ID",
null=True,
blank=True,
on_delete=models.PROTECT,
)
class Meta:
ordering = ["id"]
indexes = [
......@@ -1097,7 +1107,9 @@ class Compound(AutoFillableModel):
Replace the references to a given compound in the data with
references to another new compound. used to deal with
duplicates in the database
also delete this object
"""
self.replaced_with = replacing_compound
for ref in RefCompoundBiblio.objects.filter(compound=self):
ref.compound = replacing_compound
ref.save()
......@@ -1495,21 +1507,14 @@ class ContributionManager(models.Manager):
if current_user.is_anonymous:
qs = qs.exclude(validated=False)
elif not current_user.is_superuser:
qs = qs.exclude(
Q(validated=False),
~Q(contributor=current_user),
)
qs = qs.exclude(Q(validated=False), ~Q(contributor=current_user),)
return qs
def validated(self):
"""
Get validated contributions
"""
return (
super()
.get_queryset()
.exclude(validated=False)
)
return super().get_queryset().exclude(validated=False)
class Contribution(models.Model):
......@@ -1551,11 +1556,6 @@ def update_compound_cached_properties(compounds_queryset=None):
)
c.save()
compounds_queryset.update(
pubs=Subquery(
compounds_queryset.filter(id=OuterRef("id"))
.annotate(_pubs=Count("refcompoundbiblio", distinct=True))
.values("_pubs")[:1]
),
best_activity=Subquery(
compounds_queryset.filter(id=OuterRef("id"))
.annotate(
......@@ -1566,11 +1566,18 @@ def update_compound_cached_properties(compounds_queryset=None):
)
.values("_best_activity")[:1]
),
)
compounds_queryset.update(
pubs=Subquery(
compounds_queryset.filter(id=OuterRef("id"))
.annotate(_pubs=Count("refcompoundbiblio", distinct=True))
.values("_pubs")[:1]
),
le=Subquery(
compounds_queryset.filter(id=OuterRef("id"))
.annotate(
_le=Cast(
1.37 * Max("compoundactivityresult__activity") / F("nb_atom_non_h"),
1.37 * F("best_activity") / F("nb_atom_non_h"),
FloatField(),
)
)
......@@ -1580,7 +1587,7 @@ def update_compound_cached_properties(compounds_queryset=None):
compounds_queryset.filter(id=OuterRef("id"))
.annotate(
_lle=Cast(
Max("compoundactivityresult__activity") - F("a_log_p"), FloatField()
F("best_activity") - F("a_log_p"), FloatField()
)
)
.values("_lle")[:1]
......@@ -1814,9 +1821,7 @@ 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(id=OuterRef("id"))),
cytoxtest_av=Exists(
CompoundCytotoxicityResult.objects.filter(id=OuterRef("id"))
),
......
......@@ -224,7 +224,7 @@ Description: IPPI-DB Theme
}
.input_field {
width: auto;
width: 100%;
margin-right: 2px;
font-family: "BrandonGrotesqueReg";
text-align: left;
......
......@@ -895,7 +895,7 @@ div.hidden {
}
.form_div-fluid {
width: 100%;
width: auto;
padding: 1em;
}
......
function test_type_changed(source){
var cell_line_input = document.getElementById(source.id.replace("test_type","cell_line_name")).parentNode;
if (source.value=="CELL"){
cell_line_input.style.display = '';
cell_line_input.style.visibility = '';
}else{
cell_line_input.style.display = 'none';
cell_line_input.style.visibility = 'hidden';
}
}
\ No newline at end of file
......@@ -22,17 +22,23 @@ $(document).ready(function () {
//Function to load different template setting on Composition page
function onloadTest(type, choice) {
function onloadTest(type, choice) {
console.log("Onload Test:", type, choice);
var total = $('#id_' + 'ProteinDomainComplexForm' + '-TOTAL_FORMS').val();
console.log("total: ",total);
if (type == "Hetero2merAB" && choice == "inhibited" && total < 2) {
console.log(document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value);
cloneMoreFull('.inline_box_complex_long:last', 'ProteinDomainComplexForm');
document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value = "1";
document.getElementById('id_ProteinDomainComplexForm-1-complex_type_1').value = "Partner";
} else if (type == "Homo2merA2" && choice == "inhibited" && total < 2) {
cloneMoreFull('.inline_box_complex_long:last', 'ProteinDomainComplexForm');
document.getElementById('id_ProteinDomainComplexForm-0-complex_type_0').value = "Bound";
} else if (type == "Hetero2merAB" && choice == "stabilized" && total < 2) {
console.log(document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value);
cloneMoreFull('.inline_box_complex_long:last', 'ProteinDomainComplexForm');
document.getElementById('id_ProteinDomainComplexForm-1-complex_type_1').value = "Bound";
document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value = "1";
document.getElementById('id_ProteinDomainComplexForm-1-complex_type_1').value = "Partner";
} else if (type == "HomoLike2mer" && choice == "stabilized" && total < 2) {
cloneMoreFull('.inline_box_complex_long:last', 'ProteinDomainComplexForm');
document.getElementById('id_ProteinDomainComplexForm-1-complex_type_1').value = "Bound";
......@@ -45,6 +51,7 @@ function onloadTest(type, choice) {
cloneMoreFull('.inline_box_complex_long:last', 'ProteinDomainComplexForm');
document.getElementById('id_ProteinDomainComplexForm-1-complex_type_1').value = "Partner";
} else if (type == "Homo3merA3" || type == "RingHomo3mer" && choice == "stabilized") {
removeMoreFull('.inline_box_complex_long:last', 'ProteinDomainComplexForm');
document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value = "3";
} else if (type == "Homo4merA4" && choice == "stabilized") {
document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value = "4";
......@@ -53,10 +60,10 @@ function onloadTest(type, choice) {
} else if (type == "RingHomo5mer" && choice == "stabilized") {
document.getElementById('id_ProteinDomainComplexForm-0-ppc_copy_nb').value = "5";
}
}
}
//Function to load different template setting on PPI page
function onloadTestPPI(type, choice) {
/* function onloadTestPPI(type, choice) {
console.log("Onload Test PPI:", type, choice);
if (type == "Homo2merA2" && choice == "inhibited") {
document.getElementById('id_PpiForm-cc_nb').value = "2";
......@@ -89,7 +96,7 @@ function onloadTestPPI(type, choice) {
document.getElementById('id_PpiForm-cc_nb').value = "1";
document.getElementById('id_PpiForm-symmetry').value = "8";
}
}
} */
// Function to duplicate form and increment ids
function cloneMoreFull(selector, prefix) {
......
......@@ -625,7 +625,7 @@ def launch_validate_contributions(contribution_ids: List[int]):
run_update_compound_cached_properties.s(),
run_compute_drugbank_similarity.s(),
run_validate.s(),
)
),
)
contribution_jobs.append(compounds_properties_computation_group)
# compounds_properties_computation_group.delay()
......
......@@ -31,9 +31,12 @@ function update_partner_bound_fields(archi){
}
$(document).ready(function(){
let archi = document.getElementById("archi_type").innerHTML;
let complex = document.getElementById("complex_type").innerHTML;
onloadTest(archi,complex);
$("select.complex_readonly").each(function(i,o){
$(o).change(update_partner_bound_fields(archi));
$(o).change(update_partner_bound_fields_visibility);
$(o).change(onloadTest(archi,complex));
$(o).change();
});
......@@ -44,9 +47,9 @@ $(document).ready(function(){
{%block step_desc%}
For the PDB code: <a href="http://www.rcsb.org/structure/{{pdb}}" target="_blank">{{pdb}}</a><br>
{% if "Inhib_" in complex_type %}
You have selected an <span style="font-family: BrandonGrotesqueBld;" id="archi_type">{{ complex_type|cut:"Inhib_"}}</span> that is <span style="font-family: BrandonGrotesqueBld;">{{ complex_choice }}</span> by the binding of PPI modulator.
You have selected an <span style="font-family: BrandonGrotesqueBld;" id="archi_type">{{ complex_type|cut:"Inhib_"}}</span> that is <span style="font-family: BrandonGrotesqueBld;" id="complex_type">{{ complex_choice }}</span> by the binding of PPI modulator.
{% elif "Stab_" in complex_type %}
You have selected an <span style="font-family: BrandonGrotesqueBld;" id="archi_type">{{ complex_type|cut:"Stab_"}}</span> that is <span style="font-family: BrandonGrotesqueBld;">{{ complex_choice }}</span> by the binding of PPI modulator.
You have selected an <span style="font-family: BrandonGrotesqueBld;" id="archi_type">{{ complex_type|cut:"Stab_"}}</span> that is <span style="font-family: BrandonGrotesqueBld;" id="complex_type">{{ complex_choice }}</span> by the binding of PPI modulator.
{%endif%}
<br/>
Please select the protein that is bound by the modulator and also the protein partner if applicable. You also need to specify the PFAM protein domain(s).
......
......@@ -6,7 +6,8 @@
<script src="/static/js/ippidb-charts.js" type="text/javascript"></script>
{% endblock %}
{% block title %}compound {{ compound.id }} detail{% if compound.common_name %} ({{compound.common_name}}){% endif %}{% endblock %}
{% block title %}compound {{ compound.id }} detail{% if compound.common_name %}
({{compound.common_name}}){% endif %}{% endblock %}
{% block content %}
<div id="mainnav">
......@@ -36,7 +37,9 @@
{% include "compound_smiles_draw.html" with id=compound.id smile=compound.canonical_smile width=250 height=250%}
<div style="display: flex;
align-items: center;">
{% if compound.is_validated is False %}
{% if compound.replaced_with is not None %}
<h1 class="page-title-warning" style="margin: 0;">Compound {{ compound.id }} - This compound is replaced with <a href="/compounds/{{ compound.replaced_with.id }}">compound {{ compound.replaced_with.id }}</a> </h1>
{% elif compound.is_validated is False %}
<h1 class="page-title-warning" style="margin: 0;">Compound {{ compound.id }} - This compound has not been
validated by a curator yet, data might be incomplete or
inaccurate</h1>
......@@ -61,7 +64,8 @@
<div class="tab-pane fade" id="physicochemistry" role="tabpanel" aria-labelledby="physicochemistry-tab">
<div class="row d-flex justify-content-center">
<div class="col-sm-12 col-md-9" style="margin: 10px;">
<h5 class="card_title">Physicochemical filters <span class="info_point" onclick="showLegend('show_legend_physico')"><i class="fas fa-info-circle"></i></span>
<h5 class="card_title">Physicochemical filters <span class="info_point"
onclick="showLegend('show_legend_physico')"><i class="fas fa-info-circle"></i></span>
</h5>
<div id="show_legend_physico" style="display: none; padding:8px;">
<div class="row d-flex justify-content-center" style=" box-shadow: 0 3px 11px 0 rgba(0, 0, 0, 0.2);
......@@ -212,7 +216,7 @@
<td class="text-center {% status_class compound.veber_tpsa %}" title="TPSA <= 140">
</td>
<td class="text-center {% status_class compound.pfizer_tpsa %}" title="TPSA >= 75">
</tr>
</tr>
<tr>
<th scope="row">RB</th>
<td>{{ compound.nb_rotatable_bonds | default_if_none:"not available"}}</td>
......@@ -224,94 +228,96 @@
</tbody>
</table>
</div>
<div class="col" style="margin: 10px;">
<h5 class="card_title">Radar chart<span class="info_point" onclick="showLegend('show_legend_radar')"> <i class="fas fa-info-circle"></i></span>
</h5>
<div id="show_legend_radar" style="display: none; padding:8px;">
<div class="row d-flex justify-content-center" style=" box-shadow: 0 3px 11px 0 rgba(0, 0, 0, 0.2);
padding-top: 9px;">
<div class="col-8">
<div style="border: 1px solid #f2f2f2;">
<div style=" background-color: #f2f2f2;text-align: center; font-family:'BrandonGrotesqueBld';">
Caption
</div>
<div style="padding: 5px;">
<p><i class="fas fa-draw-polygon" style="color:#ff6384;"></i> Descriptor's value for the
compound</p>
<p><i class="fas fa-draw-polygon" style="color:#36a2eb;"></i> Descriptor's threshold</p>
<p>Those thresholds correspond either to the limits of both the Lipinski's RO5 and Veber's rule,
or to the rule of thumb of Ritchie for the number of aromatic rings - Ar, and the mean values
usually observed among drugs for Fsp3 and the number of chiral centers - R/S.</p>
</div>
</div>
<div class="col-sm-12 col-md-9" style="margin: 10px;">
<h5 class="card_title">Radar chart<span class="info_point" onclick="showLegend('show_legend_radar')"> <i
class="fas fa-info-circle"></i></span>
</h5>
<div id="show_legend_radar" style="display: none; padding:8px;">
<div class="row d-flex justify-content-center" style=" box-shadow: 0 3px 11px 0 rgba(0, 0, 0, 0.2);
padding-top: 9px;">
<div class="col-8">
<div style="border: 1px solid #f2f2f2;">
<div style=" background-color: #f2f2f2;text-align: center; font-family:'BrandonGrotesqueBld';">
Caption
</div>
<div style="padding: 5px;">
<p><i class="fas fa-draw-polygon" style="color:#ff6384;"></i> Descriptor's value for the
compound</p>
<p><i class="fas fa-draw-polygon" style="color:#36a2eb;"></i> Descriptor's threshold</p>
<p>Those thresholds correspond either to the limits of both the Lipinski's RO5 and Veber's rule,
or to the rule of thumb of Ritchie for the number of aromatic rings - Ar, and the mean values
usually observed among drugs for Fsp3 and the number of chiral centers - R/S.</p>
</div>
</div>
<div class="col-4">
<table class="table table-striped legend_table">
<thead>
<tr>
<th>Short name</th>
<th>Threshold</th>
</tr>
</thead>
<tbody>
<tr>
<td>MW</td>
<td>≤ 500 g/mol</td>
</tr>
<tr>
<td>AlogP</td>
<td>≤ 5</td>
</tr>
<tr>
<td>HBD</td>
<td>≤ 5</td>
</tr>
<tr>
<td>HBA</td>
<td>≤ 10</td>
</tr>
<tr>
<td>TPSA</td>
<td>≤ 140 Å<sup>2</sup></td>
</tr>
<tr>
<td>RB</td>
<td>≤ 10</td>
</tr>
<tr>
<td>ArRing</td>
<td>≤ 4</td>
</tr>
<tr>
<td>Fsp3</td>
<td>≥ 0.4</td>
</tr>
<tr>
<td>R/S</td>
<td>≥ 1</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="card_border">
{% if compound.molecular_weight is not None %}
<canvas id="radar" data-radarh="500px" data-radarw="500px"></canvas>
<script>
$('a.second_nav').on('shown.bs.tab', function (e) {
drawCompoundDescriptorRadarChart('radar', {{ compound.molecular_weight }}, {{ compound.a_log_p }}, {{ compound.nb_donor_h }}, {{ compound.nb_acceptor_h }}, {{ compound.tpsa }}, {{ compound.nb_rotatable_bonds }}, {{ compound.nb_benzene_like_rings }}, {{ compound.fsp3 }}, {{ compound.nb_chiral_centers }});
});
</script>
{% else %}
<p class="text-secondary">Compound properties unavailable</p>
{% endif %}
<div class="col-4">
<table class="table table-striped legend_table">
<thead>
<tr>
<th>Short name</th>
<th>Threshold</th>
</tr>
</thead>
<tbody>
<tr>
<td>MW</td>
<td>≤ 500 g/mol</td>
</tr>
<tr>
<td>AlogP</td>
<td>≤ 5</td>
</tr>
<tr>
<td>HBD</td>
<td>≤ 5</td>
</tr>
<tr>
<td>HBA</td>
<td>≤ 10</td>
</tr>
<tr>
<td>TPSA</td>
<td>≤ 140 Å<sup>2</sup></td>
</tr>
<tr>
<td>RB</td>
<td>≤ 10</td>
</tr>
<tr>
<td>ArRing</td>
<td>≤ 4</td>
</tr>
<tr>
<td>Fsp3</td>
<td>≥ 0.4</td>
</tr>
<tr>
<td>R/S</td>
<td>≥ 1</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="card_border">
{% if compound.molecular_weight is not None %}
<canvas id="radar" data-radarh="500px" data-radarw="500px"></canvas>
<script>
$('a.second_nav').on('shown.bs.tab', function (e) {
drawCompoundDescriptorRadarChart('radar', {{ compound.molecular_weight }}, {{ compound.a_log_p }}, {{ compound.nb_donor_h }}, {{ compound.nb_acceptor_h }}, {{ compound.tpsa }}, {{ compound.nb_rotatable_bonds }}, {{ compound.nb_benzene_like_rings }}, {{ compound.fsp3 }}, {{ compound.nb_chiral_centers }});
});
</script>
{% else %}
<p class="text-secondary">Compound properties unavailable</p>
{% endif %}
</div>
</div>
</div>
{% if pca_biplot_data %}
<div class="row d-flex justify-content-center">
<div class="col-sm-12 col-md-9" style="margin: 10px;">
<div class="col-sm-12 col-md-9">
<h5 class="card_title">PCA : iPPI-DB chemical space</h5>
<div class="card_border">
......@@ -321,46 +327,48 @@
</script>
</div>