Skip to content
This repository has been archived by the owner on Jan 18, 2020. It is now read-only.

Integrate JBrowse into Varify #356

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,58 @@ or run a `uwsgi` process:
uwsgi --ini server/uwsgi/local.ini --protocol http --socket 127.0.0.1:8000 --check-static _site
```

## Optional JBrowse Setup

*Note: Varify disables Alamut and JBrowse if nothing is running on settings.ALAMUT_URL and settings.JBROWSE_HOST, respectively. To hide, comment out one or both buttons in varify/static/templates/variant/summary.html.*

Install JBrowse in $project_root/jbrowse

```bash
curl -O http://jbrowse.org/releases/JBrowse-x.x.x.zip (ie 1.11.3)
unzip JBrowse-x.x.x.zip -d jbrowse
cd jbrowse
./setup.sh
```

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.

```bash
location /files/ {
alias /your/directory/of/files/;
internal;
}
```

Run the commands below to load reference sequences and Cosmic track (in that order). This only needs to be done once.

```bash
sudo ./bin/prepare-refseqs.pl --fasta ../files/chr1.fa
...
sudo ./bin/prepare-refseqs.pl --fasta ../files/chrY.fa
sudo ./bin/flatfile-to-json.pl --gff ../files/ALL_COSMIC_POINT_MUTS_v65.gff3 --trackLabel Cosmic --trackType CanvasFeatures
...

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.
```

Run bgzip and tabix (via samtools/htslib) on VCF files

```bash
git clone git://github.com/samtools/samtools.git
bgzip my.vcf
tabix -p vcf my.vcf.gz
```

**Lastly, make sure data files are named correctly!** The batch, sample and version values 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.

```bash
[sample]
project = U01
batch = Pseq_batch9
sample = P-Pseq_0019-P-A
version = 1
```

## Makefile Commands

- `build` - builds and initializes all submodules, compiles SCSS and optimizes JavaScript
Expand Down
2 changes: 1 addition & 1 deletion varify/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__version_info__ = {
'major': 0,
'minor': 2,
'minor': 4,
'micro': 0,
'releaselevel': 'beta',
'serial': 1
Expand Down
3 changes: 2 additions & 1 deletion varify/conf/global_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@
TEMPLATE_CONTEXT_PROCESSORS += (
'django.core.context_processors.request',
'varify.context_processors.static',
'varify.context_processors.alamut',
'varify.context_processors.alamut'
)


Expand All @@ -188,6 +188,7 @@
LOGIN_REDIRECT_URL = '/workspace/'

ALAMUT_URL = 'http://localhost:10000'
JBROWSE_HOST = 'localhost'

# For non-publicly accessible applications, the siteauth app can be used to
# restrict access site-wide.
Expand Down
2 changes: 1 addition & 1 deletion varify/samples/formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from ordereddict import OrderedDict
from django.db.models import Q
from avocado.formatters import registry as formatters
from serrano.formatters import HTMLFormatter
from django.conf import settings
from serrano.formatters import HTMLFormatter


class AlamutFormatter(HTMLFormatter):
Expand Down
75 changes: 70 additions & 5 deletions varify/samples/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@
from varify import api
from vdw.assessments.models import Assessment
from vdw.genome.models import Chromosome
from vdw.samples.models import Sample, Result, ResultScore, ResultSet
from vdw.samples.models import (Sample, SampleManifest, Result, ResultScore,
ResultSet)
from vdw.variants.models import Variant
from .forms import ResultSetForm


log = logging.getLogger(__name__)
OPENPYXL_MAJOR_VERSION = int(openpyxl.__version__[0])

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

# Integrate the SampleManifest data
sm = SampleManifest.objects.get(sample__id=data['sample']['id'])
found = False
filestem = ''

# Add JBrowse data requirements, including sample_manifest which is
# constructed by concatenating the batch, sample and run of [sample]
for line in sm.content.split('\n'):
if '[sample]' in line:
found = True

if found:
if line.startswith('batch = ') or line.startswith('sample = '):
chunks = line.split('=')

if len(chunks) > 1:
filestem += chunks[1].strip() + '_'

if line.startswith('version = '):
chunks = line.split('=')

if len(chunks) > 1:
filestem += chunks[1].strip()
break

data['sample_manifest'] = filestem
data['jbrowse_host'] = settings.JBROWSE_HOST

try:
score = ResultScore.objects.get(result=result)
data['score'] = {
Expand Down Expand Up @@ -310,10 +340,15 @@ class ResultsResource(ThrottledResource):
template = api.templates.SampleResultVariant

def post(self, request):
if (not request.data.get('ids') or
not isinstance(request.data['ids'], list)):
return HttpResponse(status=codes.unprocessable_entity,
content='Array of "ids" is required')
ids_not_found = 'ids' not in request.data
not_a_list = not isinstance(request.data['ids'], list)

if ids_not_found or not_a_list:
return self.render(
request,
{'message': 'An array of "ids" is required'},
status=codes.unprocessable_entity
)

data = []
resource = SampleResultResource()
Expand Down Expand Up @@ -686,6 +721,31 @@ def get(self, request, pk):
return data


class JbrowseResource(ThrottledResource):
def get(self, request, filename):
response = HttpResponse()
try:
if '.bai' in filename or '.tbi' in filename:
response['Content-Type'] = 'application/octet-stream'
else:
response['Content-Type'] = 'text/plain'

# Control access to files hosted by nginx
response['X-Accel-Redirect'] = '/files/' + filename
# Control access to files hosted by Apache
response['X-Sendfile'] = '/files/' + filename

response['Content-Disposition'] = 'attachment;filename=' + filename
except Exception:
return self.render(
request,
{'message': 'No sample found for "id"'},
status=codes.unprocessable_entity
)

return response


sample_resource = never_cache(SampleResource())
samples_resource = never_cache(SamplesResource())
named_sample_resource = never_cache(NamedSampleResource())
Expand All @@ -699,6 +759,7 @@ def get(self, request, pk):

phenotype_resource = never_cache(PhenotypeResource())
pedigree_resource = never_cache(PedigreeResource())
jbrowse_resource = never_cache(JbrowseResource())

urlpatterns = patterns(
'',
Expand Down Expand Up @@ -731,6 +792,10 @@ def get(self, request, pk):
sample_result_set_resource,
name='variant-set'),

url(r'^jbrowse/(?P<filename>.+)$',
jbrowse_resource,
name='jbrowse_resource'),

url(r'^(?P<sample_id>.+)/phenotypes/$',
phenotype_resource,
name='phenotype'),
Expand Down
2 changes: 2 additions & 0 deletions varify/static/templates/variant/summary.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,5 @@ <h4><%= data.sample.label %> <small>in <%= data.sample.project %></small></h4>
</ul>

<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>

<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%22%7D%7D' target=_blank class='btn btn-primary btn-small'>Query JBrowse</a>