Skip to content

Commit 51f0304

Browse files
Merge pull request #134 from rigdenlab/development
Minor update
2 parents 281b34c + a363725 commit 51f0304

31 files changed

Lines changed: 961 additions & 441 deletions

.github/workflows/main.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ jobs:
3939
redis-version: 5
4040
- name: Run tests.py
4141
env:
42+
THIS_IS_GH_ACTIONS: 1
4243
KEYDB_URL: $ {{ secrets.KEYDB_URL }}
4344
run: |
4445
python tests.py

CHANGELOG.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@ Changelog
22
=========
33

44

5+
0.4.1
6+
-----
7+
8+
Added
9+
~~~~~
10+
- Added contact diff track with smoothed values (MCC for contacts and RMSD for distograms)
11+
12+
Changed
13+
~~~~~
14+
- Increased contrast in sequence hydrophobicity color palettes
15+
- Use AMISE to estimate bandwidth required to calculate contact density
16+
- Updated track selector layout
17+
18+
519
0.4
620
-----
721

README.md

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,25 @@ Once you have installed `redis`, you will need to start the service by running:
5959
$ sudo service redis start
6060
```
6161

62-
You will also need to create a environment variable called `KEYDB_URL` with
63-
the URL to connect to the redis server you just started on your machine:
62+
Now you'll need to clone this repository, install the requirements and setup environment variables.
63+
Please note that ConPlot requires at least `python 3.6`.
6464

6565
```bash
66-
$ KEYDB_URL=redis://localhost:6379
66+
$ git clone https://github.com/rigdenlab/conplot
67+
$ cd conplot
68+
$ python3.6 -m pip install -r requirements.txt
69+
$ echo "KEYDB_URL=0://localhost:6379" > .env
70+
$ echo "KEYDB_TIMEOUT=3600" >> .env
6771
```
6872

69-
After this, all you need to do is clone this repository, install the requirements
70-
and start the Flask development server on your machine. Please note that ConPlot
71-
requires at least `python 3.6`.
73+
With the last two commands you will also have created an `.env` file with a variable named
74+
`KEYDB_URL` pointing to the redis server and a `KEYDB_TIMEOUT` variable with the session
75+
timeout value. This is the time at which a session expires after inactivity. By default in
76+
`www.conplot.org` this has a value of 3600 minutes, but if running locally you can set this
77+
time to any other value. The only thing left to do is to start the Flask development
78+
server on your machine:
7279

7380
```bash
74-
$ git clone https://github.com/rigdenlab/conplot
75-
$ cd conplot
76-
$ python3.6 -m pip install -r requirements.txt
7781
$ python3.6 app.py
7882
```
7983

app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def serve_layout():
2424
except (keydb.ConnectionError, TypeError, KeyError) as e:
2525
app.logger.error('Redis connection error! {}'.format(e))
2626
return layouts.RedisConnectionError()
27-
session_id = session_utils.initiate_session(cache, app.logger)
27+
session_id = session_utils.initiate_session(cache, app.logger, keydb_timeout)
2828
return layouts.Base(session_id)
2929

3030

@@ -44,6 +44,7 @@ def serve_layout():
4444
'requests_pathname_prefix': '/conplot/',
4545
})
4646
keydb_pool = keydb_utils.create_pool(os.environ.get('KEYDB_URL'))
47+
keydb_timeout = os.environ.get('KEYDB_TIMEOUT')
4748
app.layout = serve_layout
4849

4950

@@ -407,7 +408,7 @@ def javascript_exe_button(n_clicks, session_id):
407408

408409
elif 'new-session' in trigger['prop_id'] or session_utils.is_expired_session(session_id, cache, app.logger):
409410
cache = keydb.KeyDB(connection_pool=keydb_pool)
410-
new_session_id = session_utils.initiate_session(cache, app.logger)
411+
new_session_id = session_utils.initiate_session(cache, app.logger, keydb_timeout)
411412
return "location.reload();", no_update, new_session_id
412413

413414
else:
@@ -454,7 +455,7 @@ def create_ConPlot(plot_click, refresh_click, factor, contact_marker_size, track
454455
if any([True for x in (factor, contact_marker_size, track_marker_size, track_separation) if x is None or x < 0]):
455456
app.logger.info('Session {} invalid display control value detected'.format(session_id))
456457
return no_update, components.InvalidInputModal(), no_update, no_update
457-
elif superimpose and ('---' in cmap_selection or len(set(cmap_selection)) == 1):
458+
elif superimpose and ('--- Empty ---' in cmap_selection or len(set(cmap_selection)) == 1):
458459
return no_update, components.InvalidMapSelectionModal(), no_update, no_update
459460

460461
app.logger.info('Session {} creating conplot'.format(session_id))

components/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ class UserReadableTrackNames(Enum):
1111
heatmap = 'Heatmap'
1212
hydrophobicity = 'Hydrophobicity'
1313
density = 'Contact density'
14+
diff = 'Contact diff'
1415

1516

1617
class EmailIssueReference(Enum):

components/cards.py

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from utils import cache_utils
12
import components
23
import dash_core_components as dcc
34
import dash_bootstrap_components as dbc
@@ -286,45 +287,47 @@ def DisplayControlCard(available_tracks=None, selected_tracks=None, selected_cma
286287
html.H5("Active tracks", className="card-text", style={'text-align': "center"}),
287288
html.Hr(),
288289
html.Br(),
289-
TrackSelectionCard('-4', selected_tracks[0], available_tracks=available_tracks),
290+
dbc.Card(components.TrackLayoutSelector('-4', available_tracks, selected_tracks[0]), outline=False),
290291
html.Br(),
291-
TrackSelectionCard('-3', selected_tracks[1], available_tracks=available_tracks),
292+
dbc.Card(components.TrackLayoutSelector('-3', available_tracks, selected_tracks[1]), outline=False),
292293
html.Br(),
293-
TrackSelectionCard('-2', selected_tracks[2], available_tracks=available_tracks),
294+
dbc.Card(components.TrackLayoutSelector('-2', available_tracks, selected_tracks[2]), outline=False),
294295
html.Br(),
295-
TrackSelectionCard('-1', selected_tracks[3], available_tracks=available_tracks),
296+
dbc.Card(components.TrackLayoutSelector('-1', available_tracks, selected_tracks[3]), outline=False),
296297
html.Br(),
297-
TrackSelectionCard(' 0', selected_tracks[4], available_tracks=available_tracks),
298+
dbc.Card(components.TrackLayoutSelector('0', available_tracks, selected_tracks[4]), outline=False),
298299
html.Br(),
299-
TrackSelectionCard('+1', selected_tracks[5], available_tracks=available_tracks),
300+
dbc.Card(components.TrackLayoutSelector('+1', available_tracks, selected_tracks[5]), outline=False),
300301
html.Br(),
301-
TrackSelectionCard('+2', selected_tracks[6], available_tracks=available_tracks),
302+
dbc.Card(components.TrackLayoutSelector('+2', available_tracks, selected_tracks[6]), outline=False),
302303
html.Br(),
303-
TrackSelectionCard('+3', selected_tracks[7], available_tracks=available_tracks),
304+
dbc.Card(components.TrackLayoutSelector('+3', available_tracks, selected_tracks[7]), outline=False),
304305
html.Br(),
305-
TrackSelectionCard('+4', selected_tracks[8], available_tracks=available_tracks),
306+
dbc.Card(components.TrackLayoutSelector('+4', available_tracks, selected_tracks[8]), outline=False),
306307
html.Br(),
307308
html.Br(),
308309
html.H5("Colour palettes", className="card-text", style={'text-align': "center"}),
309310
html.Hr(),
310311
html.Br(),
311312
ColorPaletteSelectionCard('density', selected_palettes[0]),
312313
html.Br(),
313-
ColorPaletteSelectionCard('custom', selected_palettes[1]),
314+
ColorPaletteSelectionCard('diff', selected_palettes[1]),
314315
html.Br(),
315-
ColorPaletteSelectionCard('heatmap', selected_palettes[2]),
316+
ColorPaletteSelectionCard('custom', selected_palettes[2]),
316317
html.Br(),
317-
ColorPaletteSelectionCard('hydrophobicity', selected_palettes[3]),
318+
ColorPaletteSelectionCard('heatmap', selected_palettes[3]),
318319
html.Br(),
319-
ColorPaletteSelectionCard('membranetopology', selected_palettes[4]),
320+
ColorPaletteSelectionCard('hydrophobicity', selected_palettes[4]),
320321
html.Br(),
321-
ColorPaletteSelectionCard('msa', selected_palettes[5]),
322+
ColorPaletteSelectionCard('membranetopology', selected_palettes[5]),
322323
html.Br(),
323-
ColorPaletteSelectionCard('conservation', selected_palettes[6]),
324+
ColorPaletteSelectionCard('msa', selected_palettes[6]),
324325
html.Br(),
325-
ColorPaletteSelectionCard('disorder', selected_palettes[7]),
326+
ColorPaletteSelectionCard('conservation', selected_palettes[7]),
326327
html.Br(),
327-
ColorPaletteSelectionCard('secondarystructure', selected_palettes[8]),
328+
ColorPaletteSelectionCard('disorder', selected_palettes[8]),
329+
html.Br(),
330+
ColorPaletteSelectionCard('secondarystructure', selected_palettes[9]),
328331
html.Br(),
329332
])
330333
]
@@ -334,14 +337,6 @@ def DisplayControlCard(available_tracks=None, selected_tracks=None, selected_cma
334337
else:
335338
raise ValueError('This should not occur! Please report.')
336339

337-
338-
def TrackSelectionCard(track_idx, track_value, available_tracks):
339-
track_options = [{'label': '---', 'value': '---'}]
340-
track_options += [{'label': fname, 'value': fname} for fname in available_tracks]
341-
342-
return dbc.Card(components.TrackLayoutSelector(track_idx, track_options, track_value), outline=False)
343-
344-
345340
def ColorPaletteSelectionCard(dataset, selected_palette):
346341
available_palettes = []
347342
for palette in color_palettes.DatasetColorPalettes.__getattr__(dataset).value:
@@ -351,7 +346,7 @@ def ColorPaletteSelectionCard(dataset, selected_palette):
351346

352347

353348
def HalfSquareSelectionCard(square_idx, selection, available_cmaps):
354-
cmap_options = [{'label': '---', 'value': '---'}]
349+
cmap_options = [{'label': '--- Empty ---', 'value': '--- Empty ---'}]
355350
cmap_options += [{'label': fname, 'value': fname} for fname in available_cmaps]
356351

357352
return dbc.Card(components.HalfSquareSelector(square_idx, cmap_options, selection), outline=False)

components/listgrpoups.py

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -191,48 +191,38 @@ def AdjustPlotHelpList():
191191
'series of input menus:',
192192
html.Ul([
193193
html.Li(['L/N selector: Change the values of ', html.I('N'),
194-
' with this selector to choose how many contacts should be '
195-
'included in the plot (L is the number of residues in the '
196-
'protein sequence, residues are sorted by their probability '
197-
'score). If you set ', html.I('N'),
198-
' to 0, then all contacts in the file will be displayed. Please '
199-
'note that only numerical values between 0 and 10 are recommended.']),
200-
html.Li('Size selector: Change the size of the contact markers in the '
201-
'plot. ConPlot will set a default value depending on the size of '
202-
'the protein you are working with, but you can still change this '
203-
'if you would like to make the markers smaller or bigger. Please '
194+
' with this selector to choose how many contacts should be included in the plot (L is '
195+
'the number of residues in the protein sequence, residues are sorted by their '
196+
'probability score). If you set ', html.I('N'),
197+
' to 0, then all contacts in the file will be displayed. Please note that only numerical '
198+
'values between 0 and 10 are recommended. Additionally, please remember that contact '
199+
'data shown for PDB files is unaltered by this selector.']),
200+
html.Li('Size selector: Change the size of the contact markers in the plot. ConPlot will set a '
201+
'default value depending on the size of the protein you are working with, but you can '
202+
'still change this if you would like to make the markers smaller or bigger. Please '
204203
'note that only numerical values between 1 and 15 are recommended.'),
205-
html.Li(['Map A and Map B selectors: These two selectors let you choose '
206-
'which contact data should be displayed on the plot. By '
207-
'default, ', html.I('Map A'),
208-
' refers to the top half triangle of the map, and ',
209-
html.I('Map B'), ' to the lower one. If the ',
210-
html.I('Superimpose Maps'),
211-
' switch is activated, then the roles of these two dropdown '
212-
'menus change: ', html.I('Map A'),
213-
' is now used to select the reference map, which will be '
214-
'compared with the secondary map selected with the ',
215-
html.I('Map B'), ' selector.']),
216-
html.Li(['Superimpose Maps Switch: As explained above, if this switch '
217-
'is activated ', html.I('Map A'),
218-
' will be used as a reference map to be compared with ',
219-
html.I('Map B'),
220-
'. In this mode, contacts will be coloured according to their '
221-
'presence in the reference map and the secondary map. Contacts '
222-
'that appear on both the reference and the secondary map will be '
223-
'coloured in black -match-, those that only appear in the '
224-
'reference in grey -absent-, and those that only appear in the '
225-
'secondary map in red -mismatch-. Please note that you can only '
226-
'use this mode if you select two different contact map files in ',
204+
html.Li(['Map A and Map B selectors: These two selectors let you choose which contact data should '
205+
'be displayed on the plot. By ' 'default, ', html.I('Map A'),
206+
' refers to the top half triangle of the map, and ', html.I('Map B'),
207+
' to the lower one. If the ', html.I('Superimpose Maps'),
208+
' switch is activated, then these roles change: ', html.I('Map A'),
209+
' is now used to select the reference map, which will be compared with the secondary map '
210+
'selected with the ', html.I('Map B'), ' selector.']),
211+
html.Li(['Superimpose Maps Switch: As explained above, if this switch is activated ',
212+
html.I('Map A'), ' will be used as a reference map to be compared with ', html.I('Map B'),
213+
'. In this mode, contacts will be coloured according to their presence in the reference '
214+
'map and the secondary map. Contacts that appear on both the reference and the secondary '
215+
'map will be coloured in black -match-, those that only appear in the reference in grey '
216+
'-absent-, and those that only appear in the secondary map in red -mismatch-. Please '
217+
'note that you can only use this mode if you select two different contact map files in ',
227218
html.I('Map A'), ' and ', html.I('Map B'), ' selectors.']),
228219
html.Li(['Create Heatmap Switch: If this switch is activated, a heatmap will be created with the '
229220
'provided residue contact information. By default, if a contact map is uploaded, the '
230221
'intensity of the colours in this heatmap will correspond with the confidence of each '
231-
'contact. Alternatively, if a residue-residue distance prediction file has been uploaded '
232-
'(', html.I('CASPRR_MODE2'),
233-
' format), the heatmap will correspond with the predicted distances for '
234-
'each residue pair oin this file. Please note that when this mode is active, the ',
235-
html.I('L/N'), ' selector and the ', html.I('Size'),
222+
'contact. Alternatively, if a residue-residue distance prediction file has been '
223+
'uploaded, the heatmap will correspond with the predicted distances for each residue '
224+
'pair oin this file. Please note that when this mode is active, the ', html.I('L/N'),
225+
' selector and the ', html.I('Size'),
236226
' selector will be disabled. You can read more about how to visualise residue-residue '
237227
'distance predictions at ',
238228
html.I('Tutorial 4. Residue-Residue distance predictions'), '.']),
@@ -242,9 +232,8 @@ def AdjustPlotHelpList():
242232
'would normally be displayed.')
243233
])],
244234
style={"font-size": "110%", 'text-align': "justify"}),
245-
html.Li(['Section 2: Adjust additional tracks. In this section you will find selectors '
246-
'that will let you control aspects about how the additional tracks are being '
247-
'displayed in the plot:',
235+
html.Li(['Section 2: Adjust additional tracks. In this section you will find selectors that will let you '
236+
'control aspects about how the additional tracks are being displayed in the plot:',
248237
html.Ul([
249238
html.Li('Size selector: Change the size of the tiles used to create the '
250239
'tracks on the diagonal of the plot. By changing this value, '
@@ -326,6 +315,15 @@ def AdditionalFormatsHelpList():
326315
html.A(html.U('here'), href=UrlIndex.CONSURF_CITATION.value),
327316
'.'],
328317
style={"font-size": "110%", 'text-align': "justify"}),
318+
html.Li(['A3M file. This is a multiple sequence alignment file that should have been obtained using the '
319+
'sequence of interest as a query. ConPlot will parse the file and calculate the MSA coverage along '
320+
'the query sequence, normalise these values (1-10) and create a track where each residue '
321+
'is coloured according to the number of sequences aligned in that particular position These '
322+
'files are used in most contact prediction pipelines, and visualising the MSA coverage can help you '
323+
'understand the quality of the information used to obtain your predictions. Several alignment tools '
324+
'will create MSA files in this format, like for example HHBLITS, which you can use '
325+
'online ', html.A(html.U('here'), href=UrlIndex.HHBLITS_URL.value), '.'],
326+
style={"font-size": "110%", 'text-align': "justify"}),
329327
html.Li(['CUSTOM file. These files are plain text files that can be created manually '
330328
'by users to include additional tracks of information to the plot. These '
331329
'files enable limitless personalisation of the contact map plot, as it '

0 commit comments

Comments
 (0)