Skip to content

Commit 281b34c

Browse files
Merge pull request #131 from rigdenlab/development
Version update
2 parents e8922a0 + a72e9c9 commit 281b34c

33 files changed

+1483
-562
lines changed

CHANGELOG.rst

+16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@ Changelog
22
=========
33

44

5+
0.4
6+
-----
7+
8+
Added
9+
~~~~~
10+
- Added contact density, sequence hydrophobicity and MSA coverage tracks
11+
- Added support for trRosetta NPZ and MapPred residue distance formats
12+
- Added support of residue distance superposition
13+
14+
Changed
15+
~~~~~
16+
- New heatmap color palette
17+
- Changed to vertical layout for verbose labels and increased verbosity
18+
- Parse PDB files as a residue distance format file
19+
20+
521
0.3.2
622
-----
723

app.py

+6-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import logging
77
import keydb
88
import psycopg2
9-
from utils import callback_utils, data_utils, session_utils, app_utils, keydb_utils, plot_utils, UrlIndex
9+
from utils import callback_utils, data_utils, session_utils, app_utils, keydb_utils, plot_utils, cache_utils, UrlIndex
1010
from dash.dash import no_update
1111
import dash_bootstrap_components as dbc
1212
from dash.dependencies import Input, Output, State, ALL, MATCH
@@ -327,6 +327,8 @@ def upload_sequence(fname, fcontent, session_id):
327327
return no_update, None, components.SessionTimedOutModal()
328328
elif not callback_utils.ensure_triggered(trigger):
329329
return callback_utils.retrieve_sequence_fname(session_id, cache), None, None
330+
elif not cache_utils.is_valid_fname(fname):
331+
return no_update, no_update, components.InvalidFnameModal(fname)
330332

331333
return data_utils.upload_sequence(fname, fcontent, session_id, cache, app.logger)
332334

@@ -347,6 +349,8 @@ def upload_contact(fname, fcontent, input_format, fname_alerts, session_id):
347349
return no_update, None, components.SessionTimedOutModal()
348350
elif not callback_utils.ensure_triggered(trigger):
349351
return callback_utils.retrieve_contact_fnames(session_id, cache), None, None
352+
elif not cache_utils.is_valid_fname(fname):
353+
return no_update, no_update, components.InvalidFnameModal(fname)
350354

351355
return data_utils.upload_dataset(fname, fcontent, input_format, fname_alerts, session_id, cache, app.logger,
352356
dataset=loaders.DatasetReference.CONTACT_MAP.value)
@@ -409,7 +413,7 @@ def javascript_exe_button(n_clicks, session_id):
409413
else:
410414
app.logger.info('Fetching example data')
411415
try:
412-
session_utils.load_session('user_1', 35, session_id, cache, app.logger)
416+
session_utils.load_session('user_1', 46, session_id, cache, app.logger)
413417
except (psycopg2.OperationalError, AttributeError) as e:
414418
app.logger.error('Unable to fetch example data: {}'.format(e))
415419
return no_update, components.ExampleSessionConnectionErrorModal(), no_update
@@ -450,8 +454,6 @@ def create_ConPlot(plot_click, refresh_click, factor, contact_marker_size, track
450454
if any([True for x in (factor, contact_marker_size, track_marker_size, track_separation) if x is None or x < 0]):
451455
app.logger.info('Session {} invalid display control value detected'.format(session_id))
452456
return no_update, components.InvalidInputModal(), no_update, no_update
453-
elif superimpose and distance_matrix:
454-
return no_update, components.InvalidSuperposeDistanceMatrixModal(), no_update, no_update
455457
elif superimpose and ('---' in cmap_selection or len(set(cmap_selection)) == 1):
456458
return no_update, components.InvalidMapSelectionModal(), no_update, no_update
457459

components/__init__.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33

44
class UserReadableTrackNames(Enum):
55
membranetopology = 'Membrane Topology'
6+
msa = 'MSA Coverage'
67
secondarystructure = 'Secondary Structure'
78
disorder = 'Seq. Disorder'
89
conservation = 'Seq. Conservation'
910
custom = 'Custom Tracks'
1011
heatmap = 'Heatmap'
12+
hydrophobicity = 'Hydrophobicity'
13+
density = 'Contact density'
1114

1215

1316
class EmailIssueReference(Enum):
@@ -28,16 +31,21 @@ def SessionStoreModal(*args, **kwargs):
2831
return SessionStoreModal(*args, **kwargs)
2932

3033

34+
def InvalidFnameModal(*args, **kwargs):
35+
from components.modals import InvalidFnameModal
36+
return InvalidFnameModal(*args, **kwargs)
37+
38+
3139
def ExampleSessionConnectionErrorModal(*args, **kwargs):
3240
from components.modals import ExampleSessionConnectionErrorModal
3341

3442
return ExampleSessionConnectionErrorModal(*args, **kwargs)
3543

3644

37-
def InvalidSuperposeDistanceMatrixModal(*args, **kwargs):
38-
from components.modals import InvalidSuperposeDistanceMatrixModal
45+
def InvalidSuperposeHeatmapModal(*args, **kwargs):
46+
from components.modals import InvalidSuperposeHeatmapModal
3947

40-
return InvalidSuperposeDistanceMatrixModal(*args, **kwargs)
48+
return InvalidSuperposeHeatmapModal(*args, **kwargs)
4149

4250

4351
def GdprPolicySectionOne(*args, **kwargs):

components/cards.py

+12-6
Original file line numberDiff line numberDiff line change
@@ -308,17 +308,23 @@ def DisplayControlCard(available_tracks=None, selected_tracks=None, selected_cma
308308
html.H5("Colour palettes", className="card-text", style={'text-align': "center"}),
309309
html.Hr(),
310310
html.Br(),
311-
ColorPaletteSelectionCard('membranetopology', selected_palettes[0]),
311+
ColorPaletteSelectionCard('density', selected_palettes[0]),
312312
html.Br(),
313-
ColorPaletteSelectionCard('secondarystructure', selected_palettes[1]),
313+
ColorPaletteSelectionCard('custom', selected_palettes[1]),
314314
html.Br(),
315-
ColorPaletteSelectionCard('disorder', selected_palettes[2]),
315+
ColorPaletteSelectionCard('heatmap', selected_palettes[2]),
316316
html.Br(),
317-
ColorPaletteSelectionCard('conservation', selected_palettes[3]),
317+
ColorPaletteSelectionCard('hydrophobicity', selected_palettes[3]),
318318
html.Br(),
319-
ColorPaletteSelectionCard('custom', selected_palettes[4]),
319+
ColorPaletteSelectionCard('membranetopology', selected_palettes[4]),
320320
html.Br(),
321-
ColorPaletteSelectionCard('heatmap', selected_palettes[5]),
321+
ColorPaletteSelectionCard('msa', selected_palettes[5]),
322+
html.Br(),
323+
ColorPaletteSelectionCard('conservation', selected_palettes[6]),
324+
html.Br(),
325+
ColorPaletteSelectionCard('disorder', selected_palettes[7]),
326+
html.Br(),
327+
ColorPaletteSelectionCard('secondarystructure', selected_palettes[8]),
322328
html.Br(),
323329
])
324330
]

components/inputgroups.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from loaders import AdditionalDatasetReference
44
from parsers import ContactMapFormats, StructuralInformationFormats, DistanceInformationFormats
55
from components import EmailIssueReference, UserReadableTrackNames
6-
from utils.plot_utils import PaletteDefaultLayout
6+
from utils.color_palettes import PaletteDefaultLayout
77
from utils import UrlIndex
88

99

components/listgrpoups.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def TutorialList():
9494
TutorialItem(idx=2, name='Compare a contact prediction with a PDB file'),
9595
TutorialItem(idx=3, name='Storing, loading and sharing a session'),
9696
TutorialItem(idx=4, name='Residue-Residue distance predictions'),
97-
#TutorialItem(idx=5, name='Video tutorial')
97+
# TutorialItem(idx=5, name='Video tutorial')
9898
], style={'width': '75%'}
9999
), justify='center', align='center')
100100

@@ -397,9 +397,12 @@ def MandatoryInputHelpList():
397397
html.Ul([
398398
html.Li(['Residue Distance Prediction: these files contain information about real value distances '
399399
'between residue pairs, and are rapidly replacing contact prediction maps in protein '
400-
'structure prediction pipelines. ConPlot currently supports CASP RR MODE 2 format, the '
401-
'specifications for this format can be found ',
402-
html.A(html.U('here'), href=UrlIndex.CASP14_RRFORMAT.value), '.']),
400+
'structure prediction pipelines. ConPlot currently supports three formats: CASP RR MODE '
401+
'2 format (read more ', html.A(html.U('here'), href=UrlIndex.CASP14_RRFORMAT.value),
402+
'), MapPred output files (get them ',
403+
html.A(html.U('here'), href=UrlIndex.MAPPRED_SERVER.value),
404+
') and trRosetta npz files (get them ',
405+
html.A(html.U('here'), href=UrlIndex.TRROSETTA_SERVER.value), ').']),
403406
html.Li(['Contact Maps: There are many formats used for such files, but ConPlot is able to parse '
404407
'the most common ones. If you wish to upload a contact map file in a format not '
405408
'supported by ConPlot, we suggest you take a look at ',
@@ -488,11 +491,14 @@ def PaletteItem(idx, name):
488491
def PaletteList():
489492
return dbc.Row(
490493
dbc.ListGroup([
491-
PaletteItem(idx=1, name='Conservation'),
492-
PaletteItem(idx=2, name='Custom files'),
493-
PaletteItem(idx=3, name='Disorder'),
494-
PaletteItem(idx=4, name='Membrane Topology'),
495-
PaletteItem(idx=5, name='Secondary Structure'),
496-
PaletteItem(idx=6, name='Heatmap')
494+
PaletteItem(idx=1, name='Contact Density'),
495+
PaletteItem(idx=2, name='Conservation'),
496+
PaletteItem(idx=3, name='Custom files'),
497+
PaletteItem(idx=4, name='Disorder'),
498+
PaletteItem(idx=5, name='Membrane Topology'),
499+
PaletteItem(idx=6, name='MSA Coverage'),
500+
PaletteItem(idx=7, name='Secondary Structure'),
501+
PaletteItem(idx=8, name='Hydrophobicity'),
502+
PaletteItem(idx=9, name='Heatmap'),
497503
], style={'width': '75%'}
498504
), justify='center', align='center')

components/modals.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ def InvalidMapSelectionModal():
6060
], id='invalid-map-selection-modal', is_open=True)
6161

6262

63-
def InvalidSuperposeDistanceMatrixModal():
63+
def InvalidSuperposeHeatmapModal():
6464
return dbc.Modal([
6565
ModalHeader("Invalid Input"),
6666
dbc.ModalBody([
67-
html.P("""Superposition of heatmaps is not supported yet!""",
68-
style={'text-align': "justify"})
67+
html.P("""Superposition of residue contact predictions is not supported while the heatmap mode is
68+
activated.""", style={'text-align': "justify"})
6969
]),
7070
], id='invalid-map-selection-modal', is_open=True)
7171

@@ -101,6 +101,16 @@ def InvalidInputModal():
101101
], id='invalid-input-modal', is_open=True)
102102

103103

104+
def InvalidFnameModal(fname):
105+
return dbc.Modal([
106+
ModalHeader("Invalid file name"),
107+
dbc.ModalBody(
108+
html.P("""Sorry but we cannot process files named '{}'. You will need to rename your file.""".format(fname),
109+
style={'text-align': "justify"})
110+
),
111+
], id='invalid-fname-modal', is_open=True)
112+
113+
104114
def SessionTimedOutModal():
105115
return dbc.Modal([
106116
ModalHeader("Session timed-out"),

layouts/help.py

+9-6
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,15 @@ def Body(cache):
1010
html.Br(),
1111
html.Br(),
1212
html.Br(),
13-
components.PaletteModal('conservation', 1),
14-
components.PaletteModal('custom', 2),
15-
components.PaletteModal('disorder', 3),
16-
components.PaletteModal('membranetopology', 4),
17-
components.PaletteModal('secondarystructure', 5),
18-
components.PaletteModal('heatmap', 6),
13+
components.PaletteModal('density', 1),
14+
components.PaletteModal('conservation', 2),
15+
components.PaletteModal('custom', 3),
16+
components.PaletteModal('disorder', 4),
17+
components.PaletteModal('membranetopology', 5),
18+
components.PaletteModal('msa', 6),
19+
components.PaletteModal('secondarystructure', 7),
20+
components.PaletteModal('hydrophobicity', 8),
21+
components.PaletteModal('heatmap', 9),
1922
components.GdprPolicyModal(),
2023
components.TutorialOneModal(),
2124
components.TutorialTwoModal(),

loaders/__init__.py

+102-1
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,50 @@
11
from enum import Enum
22
import base64
3+
from parsers import HydrophobicityStates
34

45

56
class DatasetReference(Enum):
67
SEQUENCE = 'sequence'
8+
HYDROPHOBICITY = 'hydrophobicity'
79
CONTACT_MAP = 'contact'
10+
CONTACT_DENSITY = 'density'
811
MEMBRANE_TOPOLOGY = 'membranetopology'
912
SECONDARY_STRUCTURE = 'secondarystructure'
1013
CONSERVATION = 'conservation'
1114
DISORDER = 'disorder'
1215
CUSTOM = 'custom'
16+
MSA = 'msa'
1317

1418
@classmethod
1519
def exclude_seq(cls):
1620
for item in cls:
17-
if item.value != 'sequence':
21+
if item.value != 'sequence' and item.value != 'hydrophobicity':
1822
yield item
1923

2024

2125
class AdditionalDatasetReference(Enum):
26+
A3M = DatasetReference.MSA.value
2227
TOPCONS = DatasetReference.MEMBRANE_TOPOLOGY.value
2328
PSIPRED = DatasetReference.SECONDARY_STRUCTURE.value
2429
IUPRED = DatasetReference.DISORDER.value
2530
CONSURF = DatasetReference.CONSERVATION.value
2631
CUSTOM = DatasetReference.CUSTOM.value
2732

33+
@classmethod
34+
def include_hydrophobicity(cls):
35+
new_enum = Enum('AdditionalDatasetReference', {
36+
'A3M': DatasetReference.MSA.value,
37+
'TOPCONS': DatasetReference.MEMBRANE_TOPOLOGY.value,
38+
'PSIPRED': DatasetReference.SECONDARY_STRUCTURE.value,
39+
'IUPRED': DatasetReference.DISORDER.value,
40+
'CONSURF': DatasetReference.CONSERVATION.value,
41+
'CUSTOM': DatasetReference.CUSTOM.value,
42+
'HYDROPHOBICITY': DatasetReference.HYDROPHOBICITY.value
43+
})
44+
45+
for item in new_enum:
46+
yield item
47+
2848

2949
def decode_raw_file(raw_file):
3050
content_type, content_string = raw_file.split(',')
@@ -43,3 +63,84 @@ def SequenceLoader(*args, **kwargs):
4363
from loaders.sequenceloader import SequenceLoader
4464

4565
return SequenceLoader(*args, **kwargs)
66+
67+
68+
STATES = {
69+
DatasetReference.MEMBRANE_TOPOLOGY.value: {
70+
1: 'INSIDE',
71+
2: 'OUTSIDE',
72+
3: 'INSERTED'
73+
},
74+
DatasetReference.CONSERVATION.value: {
75+
1: 'VARIABLE_1',
76+
2: 'VARIABLE_2',
77+
3: 'VARIABLE_3',
78+
4: 'AVERAGE_4',
79+
5: 'AVERAGE_5',
80+
6: 'AVERAGE_6',
81+
7: 'CONSERVED_7',
82+
8: 'CONSERVED_8',
83+
9: 'CONSERVED_9'
84+
},
85+
DatasetReference.CUSTOM.value: {
86+
1: 'CUSTOM_1',
87+
2: 'CUSTOM_2',
88+
3: 'CUSTOM_3',
89+
4: 'CUSTOM_4',
90+
5: 'CUSTOM_5',
91+
6: 'CUSTOM_6',
92+
7: 'CUSTOM_7',
93+
8: 'CUSTOM_8',
94+
9: 'CUSTOM_9',
95+
10: 'CUSTOM_10',
96+
11: 'CUSTOM_11',
97+
'NAN': 'CUSTOM_NAN'
98+
},
99+
DatasetReference.DISORDER.value: {
100+
1: 'DISORDER',
101+
2: 'ORDER'
102+
},
103+
DatasetReference.SECONDARY_STRUCTURE.value: {
104+
1: 'HELIX',
105+
2: 'COIL',
106+
3: 'SHEET'
107+
},
108+
DatasetReference.HYDROPHOBICITY.value: {
109+
0: 'HYDROPATHY_0',
110+
1: 'HYDROPATHY_1',
111+
2: 'HYDROPATHY_2',
112+
3: 'HYDROPATHY_3',
113+
4: 'HYDROPATHY_4',
114+
5: 'HYDROPATHY_5',
115+
6: 'HYDROPATHY_6',
116+
7: 'HYDROPATHY_7',
117+
8: 'HYDROPATHY_8',
118+
9: 'HYDROPATHY_9',
119+
10: 'HYDROPATHY_10'},
120+
DatasetReference.CONTACT_DENSITY.value: {
121+
0: 'CONTACT_DENSITY_0',
122+
1: 'CONTACT_DENSITY_1',
123+
2: 'CONTACT_DENSITY_2',
124+
3: 'CONTACT_DENSITY_3',
125+
4: 'CONTACT_DENSITY_4',
126+
5: 'CONTACT_DENSITY_5',
127+
6: 'CONTACT_DENSITY_6',
128+
7: 'CONTACT_DENSITY_7',
129+
8: 'CONTACT_DENSITY_8',
130+
9: 'CONTACT_DENSITY_9',
131+
10: 'CONTACT_DENSITY_10',
132+
},
133+
DatasetReference.MSA.value: {
134+
0: 'MSA_COVERAGE_0',
135+
1: 'MSA_COVERAGE_1',
136+
2: 'MSA_COVERAGE_2',
137+
3: 'MSA_COVERAGE_3',
138+
4: 'MSA_COVERAGE_4',
139+
5: 'MSA_COVERAGE_5',
140+
6: 'MSA_COVERAGE_6',
141+
7: 'MSA_COVERAGE_7',
142+
8: 'MSA_COVERAGE_8',
143+
9: 'MSA_COVERAGE_9',
144+
10: 'MSA_COVERAGE_10',
145+
}
146+
}

0 commit comments

Comments
 (0)