Skip to content

Commit af33759

Browse files
committed
Integrate JBrowse into Varify
Supplement Alamut with JBrowse Fixes chop-dbhi#338 Signed-off-by: Ryan O'Hara <[email protected]>
1 parent 94f9e1f commit af33759

File tree

5 files changed

+127
-7
lines changed

5 files changed

+127
-7
lines changed

README.md

+52
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,58 @@ or run a `uwsgi` process:
164164
uwsgi --ini server/uwsgi/local.ini --protocol http --socket 127.0.0.1:8000 --check-static _site
165165
```
166166

167+
## Optional JBrowse Setup
168+
169+
*Note: By default, both Alamut and JBrowse are enabled. To disable, comment out one or both buttons in varify/static/templates/variant/summary.html.*
170+
171+
Install JBrowse in $project_root/jbrowse
172+
173+
```bash
174+
curl -O http://jbrowse.org/releases/JBrowse-x.x.x.zip (ie 1.11.3)
175+
unzip JBrowse-x.x.x.zip -d jbrowse
176+
cd jbrowse
177+
./setup.sh
178+
```
179+
180+
Download data files (ie BAM, GFF, VCF) to /your/directory/of/files/ and add the following to nginx.conf. This corresponds to the JbrowseResource endpoint defined in varify/samples/resources.py.
181+
182+
```bash
183+
location /files/ {
184+
alias /your/directory/of/files/;
185+
internal;
186+
}
187+
```
188+
189+
Run the commands below to load reference sequences and Cosmic track (in that order). This only needs to be done once.
190+
191+
```bash
192+
sudo ./bin/prepare-refseqs.pl --fasta ../files/chr1.fa
193+
...
194+
sudo ./bin/prepare-refseqs.pl --fasta ../files/chrY.fa
195+
sudo ./bin/flatfile-to-json.pl --gff ../files/ALL_COSMIC_POINT_MUTS_v65.gff3 --trackLabel Cosmic --trackType CanvasFeatures
196+
...
197+
198+
Note: Segment large Cosmic GFF files with synchronization marks, a line containing '###', to prevent (really) slow loading. Once a loading script executes, a data directory will exist in $project_root/jbrowse.
199+
```
200+
201+
Run bgzip and tabix (via samtools/htslib) on VCF files
202+
203+
```bash
204+
git clone git://github.com/samtools/samtools.git
205+
bgzip my.vcf
206+
tabix -p vcf my.vcf.gz
207+
```
208+
209+
**Lastly, make sure data files are named correctly!** Currently, the batch, sample and run sections of the [sample] section of the sample manifest are concatenated and delimited by '_' to create the filename root for the BAM, BAI, VCF, and TBI files in the JBrowse URL. Suffixes are hard-coded '.sorted.mdup.bam','.sorted.mdup.bam.bai','.var_raw.vcf.gz', and '.var_raw.vcf.gz.tbi', respectively.
210+
211+
```bash
212+
[sample]
213+
project = U01
214+
batch = Pseq_batch9
215+
sample = P-Pseq_0019-P-A
216+
version = 1
217+
```
218+
167219
## Makefile Commands
168220

169221
- `build` - builds and initializes all submodules, compiles SCSS and optimizes JavaScript

varify/conf/global_settings.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@
167167
TEMPLATE_CONTEXT_PROCESSORS += (
168168
'django.core.context_processors.request',
169169
'varify.context_processors.static',
170-
'varify.context_processors.alamut',
170+
'varify.context_processors.alamut'
171171
)
172172

173173

@@ -188,6 +188,7 @@
188188
LOGIN_REDIRECT_URL = '/workspace/'
189189

190190
ALAMUT_URL = 'http://localhost:10000'
191+
JBROWSE_HOST = 'localhost'
191192

192193
# For non-publicly accessible applications, the siteauth app can be used to
193194
# restrict access site-wide.

varify/samples/formatters.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from ordereddict import OrderedDict
55
from django.db.models import Q
66
from avocado.formatters import registry as formatters
7-
from serrano.formatters import HTMLFormatter
87
from django.conf import settings
8+
from serrano.formatters import HTMLFormatter
99

1010

1111
class AlamutFormatter(HTMLFormatter):

varify/samples/resources.py

+70-5
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@
2222
from varify import api
2323
from vdw.assessments.models import Assessment
2424
from vdw.genome.models import Chromosome
25-
from vdw.samples.models import Sample, Result, ResultScore, ResultSet
25+
from vdw.samples.models import (Sample, SampleManifest, Result, ResultScore,
26+
ResultSet)
2627
from vdw.variants.models import Variant
2728
from .forms import ResultSetForm
2829

30+
2931
log = logging.getLogger(__name__)
3032
OPENPYXL_MAJOR_VERSION = int(openpyxl.__version__[0])
3133

@@ -274,6 +276,34 @@ def _cache_data(self, request, pk, key):
274276
data['variant'] = VariantResource.get(request, data['variant_id'])
275277
data.pop('variant_id')
276278

279+
# Integrate the SampleManifest data
280+
sm = SampleManifest.objects.get(sample__id=data['sample']['id'])
281+
found = False
282+
filestem = ''
283+
284+
# Add JBrowse data requirements, including sample_manifest which is
285+
# constructed by concatenating the batch, sample and run of [sample]
286+
for line in sm.content.split('\n'):
287+
if '[sample]' in line:
288+
found = True
289+
290+
if found:
291+
if line.startswith('batch = ') or line.startswith('sample = '):
292+
chunks = line.split('=')
293+
294+
if len(chunks) > 1:
295+
filestem += chunks[1].strip() + '_'
296+
297+
if line.startswith('version = '):
298+
chunks = line.split('=')
299+
300+
if len(chunks) > 1:
301+
filestem += chunks[1].strip()
302+
break
303+
304+
data['sample_manifest'] = filestem
305+
data['jbrowse_host'] = settings.JBROWSE_HOST
306+
277307
try:
278308
score = ResultScore.objects.get(result=result)
279309
data['score'] = {
@@ -310,10 +340,15 @@ class ResultsResource(ThrottledResource):
310340
template = api.templates.SampleResultVariant
311341

312342
def post(self, request):
313-
if (not request.data.get('ids') or
314-
not isinstance(request.data['ids'], list)):
315-
return HttpResponse(status=codes.unprocessable_entity,
316-
content='Array of "ids" is required')
343+
ids_not_found = 'ids' not in request.data
344+
not_a_list = not isinstance(request.data['ids'], list)
345+
346+
if ids_not_found or not_a_list:
347+
return self.render(
348+
request,
349+
{'message': 'An array of "ids" is required'},
350+
status=codes.unprocessable_entity
351+
)
317352

318353
data = []
319354
resource = SampleResultResource()
@@ -686,6 +721,31 @@ def get(self, request, pk):
686721
return data
687722

688723

724+
class JbrowseResource(ThrottledResource):
725+
def get(self, request, filename):
726+
response = HttpResponse()
727+
try:
728+
if '.bai' in filename or '.tbi' in filename:
729+
response['Content-Type'] = 'application/octet-stream'
730+
else:
731+
response['Content-Type'] = 'text/plain'
732+
733+
# Control access to files hosted by nginx
734+
response['X-Accel-Redirect'] = '/files/' + filename
735+
# Control access to files hosted by Apache
736+
response['X-Sendfile'] = '/files/' + filename
737+
738+
response['Content-Disposition'] = 'attachment;filename=' + filename
739+
except Exception:
740+
return self.render(
741+
request,
742+
{'message': 'No sample found for "id"'},
743+
status=codes.unprocessable_entity
744+
)
745+
746+
return response
747+
748+
689749
sample_resource = never_cache(SampleResource())
690750
samples_resource = never_cache(SamplesResource())
691751
named_sample_resource = never_cache(NamedSampleResource())
@@ -699,6 +759,7 @@ def get(self, request, pk):
699759

700760
phenotype_resource = never_cache(PhenotypeResource())
701761
pedigree_resource = never_cache(PedigreeResource())
762+
jbrowse_resource = never_cache(JbrowseResource())
702763

703764
urlpatterns = patterns(
704765
'',
@@ -731,6 +792,10 @@ def get(self, request, pk):
731792
sample_result_set_resource,
732793
name='variant-set'),
733794

795+
url(r'^jbrowse/(?P<filename>.+)$',
796+
jbrowse_resource,
797+
name='jbrowse_resource'),
798+
734799
url(r'^(?P<sample_id>.+)/phenotypes/$',
735800
phenotype_resource,
736801
name='phenotype'),

varify/static/templates/variant/summary.html

+2
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,5 @@ <h4><%= data.sample.label %> <small>in <%= data.sample.project %></small></h4>
4949
</ul>
5050

5151
<a href='http://localhost:10000/show?request=chr<%= data.variant.chr %>:g.<%= data.variant.pos %><%= data.variant.ref %>><%= data.variant.alt %>' target=_blank class='btn btn-primary btn-small alamut-button'>Query Alamut</a>
52+
53+
<a href='http://<%= data.jbrowse_host%>/jbrowse/?loc=chr<%= data.variant.chr %>:<%= data.variant.pos-25|0 %>..<%= data.variant.pos+25 %>&tracks=DNA,Cosmic,VCF,BAM&highlight=&addTracks=%5B%7B%22label%22%3A%22BAM%22%2C%22store%22%3A%22testStore%22%2C%22type%22%3A%22JBrowse/View/Track/Alignments2%22%7D%2C%7B%22label%22%3A%22VCF%22%2C%22store%22%3A%22testStoreTwo%22%2C%22type%22%3A%22JBrowse/View/Track/CanvasVariants%22%7D%5D&addStores=%7B%22testStore%22%3A%7B%22baiUrlTemplate%22%3A%22http%3A//<%= data.jbrowse_host%>/api/samples/jbrowse/<%= data.sample_manifest%>.sorted.mdup.bam.bai%22%2C%22type%22%3A%22JBrowse/Store/SeqFeature/BAM%22%2C%22urlTemplate%22%3A%22http%3A//<%= data.jbrowse_host%>/api/samples/jbrowse/<%= data.sample_manifest%>.sorted.mdup.bam%22%7D%2C%22testStoreTwo%22%3A%7B%22tbiUrlTemplate%22%3A%22http%3A//<%= data.jbrowse_host%>/api/samples/jbrowse/<%= data.sample_manifest%>.var_raw.vcf.gz.tbi%22%2C%22type%22%3A%22JBrowse/Store/SeqFeature/VCFTabix%22%2C%22urlTemplate%22%3A%22http%3A//<%= data.jbrowse_host%>/api/samples/jbrowse/<%= data.sample_manifest%>.var_raw.vcf.gz%22%7D%7D' target=_blank class='btn btn-primary btn-small'>Query JBrowse</a>

0 commit comments

Comments
 (0)