Skip to content

Commit

Permalink
Merge pull request #131 from rigdenlab/development
Browse files Browse the repository at this point in the history
Version update
  • Loading branch information
FilomenoSanchez authored Apr 16, 2021
2 parents e8922a0 + a72e9c9 commit 281b34c
Show file tree
Hide file tree
Showing 33 changed files with 1,483 additions and 562 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@ Changelog
=========


0.4
-----

Added
~~~~~
- Added contact density, sequence hydrophobicity and MSA coverage tracks
- Added support for trRosetta NPZ and MapPred residue distance formats
- Added support of residue distance superposition

Changed
~~~~~
- New heatmap color palette
- Changed to vertical layout for verbose labels and increased verbosity
- Parse PDB files as a residue distance format file


0.3.2
-----

Expand Down
10 changes: 6 additions & 4 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import logging
import keydb
import psycopg2
from utils import callback_utils, data_utils, session_utils, app_utils, keydb_utils, plot_utils, UrlIndex
from utils import callback_utils, data_utils, session_utils, app_utils, keydb_utils, plot_utils, cache_utils, UrlIndex
from dash.dash import no_update
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State, ALL, MATCH
Expand Down Expand Up @@ -327,6 +327,8 @@ def upload_sequence(fname, fcontent, session_id):
return no_update, None, components.SessionTimedOutModal()
elif not callback_utils.ensure_triggered(trigger):
return callback_utils.retrieve_sequence_fname(session_id, cache), None, None
elif not cache_utils.is_valid_fname(fname):
return no_update, no_update, components.InvalidFnameModal(fname)

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

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

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

Expand Down
14 changes: 11 additions & 3 deletions components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@

class UserReadableTrackNames(Enum):
membranetopology = 'Membrane Topology'
msa = 'MSA Coverage'
secondarystructure = 'Secondary Structure'
disorder = 'Seq. Disorder'
conservation = 'Seq. Conservation'
custom = 'Custom Tracks'
heatmap = 'Heatmap'
hydrophobicity = 'Hydrophobicity'
density = 'Contact density'


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


def InvalidFnameModal(*args, **kwargs):
from components.modals import InvalidFnameModal
return InvalidFnameModal(*args, **kwargs)


def ExampleSessionConnectionErrorModal(*args, **kwargs):
from components.modals import ExampleSessionConnectionErrorModal

return ExampleSessionConnectionErrorModal(*args, **kwargs)


def InvalidSuperposeDistanceMatrixModal(*args, **kwargs):
from components.modals import InvalidSuperposeDistanceMatrixModal
def InvalidSuperposeHeatmapModal(*args, **kwargs):
from components.modals import InvalidSuperposeHeatmapModal

return InvalidSuperposeDistanceMatrixModal(*args, **kwargs)
return InvalidSuperposeHeatmapModal(*args, **kwargs)


def GdprPolicySectionOne(*args, **kwargs):
Expand Down
18 changes: 12 additions & 6 deletions components/cards.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,17 +308,23 @@ def DisplayControlCard(available_tracks=None, selected_tracks=None, selected_cma
html.H5("Colour palettes", className="card-text", style={'text-align': "center"}),
html.Hr(),
html.Br(),
ColorPaletteSelectionCard('membranetopology', selected_palettes[0]),
ColorPaletteSelectionCard('density', selected_palettes[0]),
html.Br(),
ColorPaletteSelectionCard('secondarystructure', selected_palettes[1]),
ColorPaletteSelectionCard('custom', selected_palettes[1]),
html.Br(),
ColorPaletteSelectionCard('disorder', selected_palettes[2]),
ColorPaletteSelectionCard('heatmap', selected_palettes[2]),
html.Br(),
ColorPaletteSelectionCard('conservation', selected_palettes[3]),
ColorPaletteSelectionCard('hydrophobicity', selected_palettes[3]),
html.Br(),
ColorPaletteSelectionCard('custom', selected_palettes[4]),
ColorPaletteSelectionCard('membranetopology', selected_palettes[4]),
html.Br(),
ColorPaletteSelectionCard('heatmap', selected_palettes[5]),
ColorPaletteSelectionCard('msa', selected_palettes[5]),
html.Br(),
ColorPaletteSelectionCard('conservation', selected_palettes[6]),
html.Br(),
ColorPaletteSelectionCard('disorder', selected_palettes[7]),
html.Br(),
ColorPaletteSelectionCard('secondarystructure', selected_palettes[8]),
html.Br(),
])
]
Expand Down
2 changes: 1 addition & 1 deletion components/inputgroups.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from loaders import AdditionalDatasetReference
from parsers import ContactMapFormats, StructuralInformationFormats, DistanceInformationFormats
from components import EmailIssueReference, UserReadableTrackNames
from utils.plot_utils import PaletteDefaultLayout
from utils.color_palettes import PaletteDefaultLayout
from utils import UrlIndex


Expand Down
26 changes: 16 additions & 10 deletions components/listgrpoups.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def TutorialList():
TutorialItem(idx=2, name='Compare a contact prediction with a PDB file'),
TutorialItem(idx=3, name='Storing, loading and sharing a session'),
TutorialItem(idx=4, name='Residue-Residue distance predictions'),
#TutorialItem(idx=5, name='Video tutorial')
# TutorialItem(idx=5, name='Video tutorial')
], style={'width': '75%'}
), justify='center', align='center')

Expand Down Expand Up @@ -397,9 +397,12 @@ def MandatoryInputHelpList():
html.Ul([
html.Li(['Residue Distance Prediction: these files contain information about real value distances '
'between residue pairs, and are rapidly replacing contact prediction maps in protein '
'structure prediction pipelines. ConPlot currently supports CASP RR MODE 2 format, the '
'specifications for this format can be found ',
html.A(html.U('here'), href=UrlIndex.CASP14_RRFORMAT.value), '.']),
'structure prediction pipelines. ConPlot currently supports three formats: CASP RR MODE '
'2 format (read more ', html.A(html.U('here'), href=UrlIndex.CASP14_RRFORMAT.value),
'), MapPred output files (get them ',
html.A(html.U('here'), href=UrlIndex.MAPPRED_SERVER.value),
') and trRosetta npz files (get them ',
html.A(html.U('here'), href=UrlIndex.TRROSETTA_SERVER.value), ').']),
html.Li(['Contact Maps: There are many formats used for such files, but ConPlot is able to parse '
'the most common ones. If you wish to upload a contact map file in a format not '
'supported by ConPlot, we suggest you take a look at ',
Expand Down Expand Up @@ -488,11 +491,14 @@ def PaletteItem(idx, name):
def PaletteList():
return dbc.Row(
dbc.ListGroup([
PaletteItem(idx=1, name='Conservation'),
PaletteItem(idx=2, name='Custom files'),
PaletteItem(idx=3, name='Disorder'),
PaletteItem(idx=4, name='Membrane Topology'),
PaletteItem(idx=5, name='Secondary Structure'),
PaletteItem(idx=6, name='Heatmap')
PaletteItem(idx=1, name='Contact Density'),
PaletteItem(idx=2, name='Conservation'),
PaletteItem(idx=3, name='Custom files'),
PaletteItem(idx=4, name='Disorder'),
PaletteItem(idx=5, name='Membrane Topology'),
PaletteItem(idx=6, name='MSA Coverage'),
PaletteItem(idx=7, name='Secondary Structure'),
PaletteItem(idx=8, name='Hydrophobicity'),
PaletteItem(idx=9, name='Heatmap'),
], style={'width': '75%'}
), justify='center', align='center')
16 changes: 13 additions & 3 deletions components/modals.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ def InvalidMapSelectionModal():
], id='invalid-map-selection-modal', is_open=True)


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

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


def InvalidFnameModal(fname):
return dbc.Modal([
ModalHeader("Invalid file name"),
dbc.ModalBody(
html.P("""Sorry but we cannot process files named '{}'. You will need to rename your file.""".format(fname),
style={'text-align': "justify"})
),
], id='invalid-fname-modal', is_open=True)


def SessionTimedOutModal():
return dbc.Modal([
ModalHeader("Session timed-out"),
Expand Down
15 changes: 9 additions & 6 deletions layouts/help.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@ def Body(cache):
html.Br(),
html.Br(),
html.Br(),
components.PaletteModal('conservation', 1),
components.PaletteModal('custom', 2),
components.PaletteModal('disorder', 3),
components.PaletteModal('membranetopology', 4),
components.PaletteModal('secondarystructure', 5),
components.PaletteModal('heatmap', 6),
components.PaletteModal('density', 1),
components.PaletteModal('conservation', 2),
components.PaletteModal('custom', 3),
components.PaletteModal('disorder', 4),
components.PaletteModal('membranetopology', 5),
components.PaletteModal('msa', 6),
components.PaletteModal('secondarystructure', 7),
components.PaletteModal('hydrophobicity', 8),
components.PaletteModal('heatmap', 9),
components.GdprPolicyModal(),
components.TutorialOneModal(),
components.TutorialTwoModal(),
Expand Down
103 changes: 102 additions & 1 deletion loaders/__init__.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,50 @@
from enum import Enum
import base64
from parsers import HydrophobicityStates


class DatasetReference(Enum):
SEQUENCE = 'sequence'
HYDROPHOBICITY = 'hydrophobicity'
CONTACT_MAP = 'contact'
CONTACT_DENSITY = 'density'
MEMBRANE_TOPOLOGY = 'membranetopology'
SECONDARY_STRUCTURE = 'secondarystructure'
CONSERVATION = 'conservation'
DISORDER = 'disorder'
CUSTOM = 'custom'
MSA = 'msa'

@classmethod
def exclude_seq(cls):
for item in cls:
if item.value != 'sequence':
if item.value != 'sequence' and item.value != 'hydrophobicity':
yield item


class AdditionalDatasetReference(Enum):
A3M = DatasetReference.MSA.value
TOPCONS = DatasetReference.MEMBRANE_TOPOLOGY.value
PSIPRED = DatasetReference.SECONDARY_STRUCTURE.value
IUPRED = DatasetReference.DISORDER.value
CONSURF = DatasetReference.CONSERVATION.value
CUSTOM = DatasetReference.CUSTOM.value

@classmethod
def include_hydrophobicity(cls):
new_enum = Enum('AdditionalDatasetReference', {
'A3M': DatasetReference.MSA.value,
'TOPCONS': DatasetReference.MEMBRANE_TOPOLOGY.value,
'PSIPRED': DatasetReference.SECONDARY_STRUCTURE.value,
'IUPRED': DatasetReference.DISORDER.value,
'CONSURF': DatasetReference.CONSERVATION.value,
'CUSTOM': DatasetReference.CUSTOM.value,
'HYDROPHOBICITY': DatasetReference.HYDROPHOBICITY.value
})

for item in new_enum:
yield item


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

return SequenceLoader(*args, **kwargs)


STATES = {
DatasetReference.MEMBRANE_TOPOLOGY.value: {
1: 'INSIDE',
2: 'OUTSIDE',
3: 'INSERTED'
},
DatasetReference.CONSERVATION.value: {
1: 'VARIABLE_1',
2: 'VARIABLE_2',
3: 'VARIABLE_3',
4: 'AVERAGE_4',
5: 'AVERAGE_5',
6: 'AVERAGE_6',
7: 'CONSERVED_7',
8: 'CONSERVED_8',
9: 'CONSERVED_9'
},
DatasetReference.CUSTOM.value: {
1: 'CUSTOM_1',
2: 'CUSTOM_2',
3: 'CUSTOM_3',
4: 'CUSTOM_4',
5: 'CUSTOM_5',
6: 'CUSTOM_6',
7: 'CUSTOM_7',
8: 'CUSTOM_8',
9: 'CUSTOM_9',
10: 'CUSTOM_10',
11: 'CUSTOM_11',
'NAN': 'CUSTOM_NAN'
},
DatasetReference.DISORDER.value: {
1: 'DISORDER',
2: 'ORDER'
},
DatasetReference.SECONDARY_STRUCTURE.value: {
1: 'HELIX',
2: 'COIL',
3: 'SHEET'
},
DatasetReference.HYDROPHOBICITY.value: {
0: 'HYDROPATHY_0',
1: 'HYDROPATHY_1',
2: 'HYDROPATHY_2',
3: 'HYDROPATHY_3',
4: 'HYDROPATHY_4',
5: 'HYDROPATHY_5',
6: 'HYDROPATHY_6',
7: 'HYDROPATHY_7',
8: 'HYDROPATHY_8',
9: 'HYDROPATHY_9',
10: 'HYDROPATHY_10'},
DatasetReference.CONTACT_DENSITY.value: {
0: 'CONTACT_DENSITY_0',
1: 'CONTACT_DENSITY_1',
2: 'CONTACT_DENSITY_2',
3: 'CONTACT_DENSITY_3',
4: 'CONTACT_DENSITY_4',
5: 'CONTACT_DENSITY_5',
6: 'CONTACT_DENSITY_6',
7: 'CONTACT_DENSITY_7',
8: 'CONTACT_DENSITY_8',
9: 'CONTACT_DENSITY_9',
10: 'CONTACT_DENSITY_10',
},
DatasetReference.MSA.value: {
0: 'MSA_COVERAGE_0',
1: 'MSA_COVERAGE_1',
2: 'MSA_COVERAGE_2',
3: 'MSA_COVERAGE_3',
4: 'MSA_COVERAGE_4',
5: 'MSA_COVERAGE_5',
6: 'MSA_COVERAGE_6',
7: 'MSA_COVERAGE_7',
8: 'MSA_COVERAGE_8',
9: 'MSA_COVERAGE_9',
10: 'MSA_COVERAGE_10',
}
}
Loading

0 comments on commit 281b34c

Please sign in to comment.