Skip to content

Commit 49567fe

Browse files
author
Xing Han Lu
authored
Merge pull request #601 from plotly/add-pileup-demo
Add pileup demo (#minor) Former-commit-id: 555e87d
2 parents cf16cf4 + 735655f commit 49567fe

20 files changed

+1200
-0
lines changed

apps/dash-pileup-demo/Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn app:server

apps/dash-pileup-demo/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Dash Pileup Demo
2+
3+
![](./assets/demo-image.png)
4+
5+
This is a demo for the [Dash Bio](https://github.com/plotly/dash-bio) Pileup component, originally published [here](https://github.com/plotly/dash-bio/tree/master/tests/dashbio_demos/dash-pileup).
6+
7+
## Adding your own data
8+
9+
To add your own data, we recommend a data storage service such as Azure Storage to host your data on the cloud. On a high level, the steps will be:
10+
11+
1. Generate your RNA data
12+
2. Create a new storage account ([tutorial](https://docs.microsoft.com/en-us/azure/storage/common/storage-account-create?tabs=azure-portal))
13+
3. Create a new container and upload your files ([tutorial](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-portal))
14+
4. Enable CORS for your storage account through the [Azure Portal](https://portal.azure.com/) (see [discussions](https://stackoverflow.com/a/59208718/13837091))
15+
1. Select your desired "Storage Account" through the portal
16+
2. On the sidebar, choose "Settings - CORS"
17+
3. Allow origins corresponding to where your app will be hosted.
18+
19+
![](./images/azure_instructions/CORS.jpg)
20+
21+
5. Retrieve the URL of the files by right clicking on each and selecting "Copy URL"
22+
23+
![](./images/azure_instructions/url.jpg)
24+
25+
6. Update the `rna_differential` function inside *app.py* such that each link corresponds to the URL of your file uploaded to the Azure Storage container.

apps/dash-pileup-demo/app.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"scripts": {
3+
"dokku": {
4+
"predeploy": "bash predeploy.sh"
5+
}
6+
}
7+
}

apps/dash-pileup-demo/app.py

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
import os
2+
import dash_html_components as html
3+
import dash_core_components as dcc
4+
from dash.dependencies import Input, Output
5+
import dash_bio
6+
import pandas as pd
7+
import numpy as np
8+
import math
9+
import plotly.graph_objects as go
10+
11+
from layout_helper import run_standalone_app
12+
13+
text_style = {"color": "#506784", "font-family": "Open Sans"}
14+
15+
_COMPONENT_ID = "pileup-browser"
16+
17+
18+
def description():
19+
return "An interactive in-browser track viewer."
20+
21+
22+
def azure_url(file):
23+
return os.path.join(
24+
"https://sampleappsdata.blob.core.windows.net/dash-pileup-demo/rna/", file
25+
)
26+
27+
28+
def header_colors():
29+
return {
30+
"bg_color": "#0F5BA7",
31+
"font_color": "white",
32+
}
33+
34+
35+
def rna_differential(app):
36+
37+
basal_lactate = {
38+
"url": azure_url("SRR1552454.fastq.gz.sampled.bam"),
39+
"indexUrl": azure_url("SRR1552454.fastq.gz.sampled.bam.bai"),
40+
}
41+
42+
luminal_lactate = {
43+
"url": azure_url("SRR1552448.fastq.gz.sampled.bam"),
44+
"indexUrl": azure_url("SRR1552448.fastq.gz.sampled.bam.bai"),
45+
}
46+
47+
HOSTED_TRACKS = {
48+
"range": {"contig": "chr1", "start": 54986297, "stop": 54991347},
49+
"celltype": [
50+
{"viz": "scale", "label": "Scale"},
51+
{"viz": "location", "label": "Location"},
52+
{
53+
"viz": "genes",
54+
"label": "genes",
55+
"source": "bigBed",
56+
"sourceOptions": {"url": azure_url("mm10.ncbiRefSeq.sorted.bb")},
57+
},
58+
{
59+
"viz": "coverage",
60+
"label": "Basal",
61+
"source": "bam",
62+
"sourceOptions": basal_lactate,
63+
},
64+
{
65+
"viz": "pileup",
66+
"vizOptions": {"viewAsPairs": True},
67+
"label": "Basal",
68+
"source": "bam",
69+
"sourceOptions": basal_lactate,
70+
},
71+
{
72+
"viz": "coverage",
73+
"label": "Luminal",
74+
"source": "bam",
75+
"sourceOptions": luminal_lactate,
76+
},
77+
{
78+
"viz": "pileup",
79+
"label": "Luminal",
80+
"source": "bam",
81+
"sourceOptions": luminal_lactate,
82+
},
83+
],
84+
}
85+
86+
return HOSTED_TRACKS
87+
88+
89+
REFERENCE = {
90+
"label": "mm10",
91+
"url": "https://hgdownload.cse.ucsc.edu/goldenPath/mm10/bigZips/mm10.2bit",
92+
}
93+
94+
DATAPATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets/data")
95+
96+
# Differentially expressed genes (identified in R, see assets/data/rna/README.md)
97+
DE_dataframe = pd.read_csv(azure_url("DE_genes.csv"))
98+
# filter for the cell type condition
99+
DE_dataframe = DE_dataframe[
100+
DE_dataframe["Comparison"] == "luminal__v__basal"
101+
].reset_index()
102+
103+
# add SNP column
104+
DE_dataframe["SNP"] = "NA"
105+
106+
107+
# get min and max effect sizes
108+
df_min = math.floor(min(DE_dataframe["log2FoldChange"]))
109+
df_max = math.ceil(max(DE_dataframe["log2FoldChange"]))
110+
111+
112+
def layout(app):
113+
HOSTED_CASE_DICT = rna_differential(app)
114+
115+
return html.Div(
116+
id="pileup-body",
117+
className="app-body",
118+
children=[
119+
html.Div(
120+
id="pileup-control-tabs",
121+
className="control-tabs",
122+
children=[
123+
dcc.Tabs(
124+
id="pileup-tabs",
125+
value="data",
126+
children=[
127+
dcc.Tab(
128+
label="Data",
129+
value="data",
130+
children=html.Div(
131+
className="control-tab",
132+
children=[
133+
"Effect Size",
134+
dcc.RangeSlider(
135+
id="pileup-volcanoplot-input",
136+
min=df_min,
137+
max=df_max,
138+
step=None,
139+
marks={
140+
i: {"label": str(i)}
141+
for i in range(df_min, df_max + 1, 2)
142+
},
143+
value=[-1, 1],
144+
),
145+
html.Br(),
146+
dcc.Graph(
147+
id="pileup-dashbio-volcanoplot",
148+
figure=dash_bio.VolcanoPlot(
149+
dataframe=DE_dataframe,
150+
margin=go.layout.Margin(l=0, r=0, b=0),
151+
legend={
152+
"orientation": "h",
153+
"yanchor": "bottom",
154+
"y": 1.02,
155+
"bgcolor": "#f2f5fa",
156+
},
157+
effect_size="log2FoldChange",
158+
effect_size_line=[-1, 1],
159+
title="Differentially Expressed Genes",
160+
genomewideline_value=-np.log10(0.05),
161+
p="padj",
162+
snp="SNP",
163+
gene="Gene",
164+
),
165+
),
166+
],
167+
),
168+
),
169+
dcc.Tab(
170+
label="About",
171+
value="what-is",
172+
children=html.Div(
173+
className="control-tab",
174+
children=[
175+
html.H4(
176+
className="what-is",
177+
children="What is pileup.js?",
178+
),
179+
dcc.Markdown(
180+
"""
181+
The Dash pileup.js component is a high-performance genomics
182+
data visualization component developed originally by the Hammer Lab
183+
(https://github.com/hammerlab/pileup.js). pileup.js
184+
supports visualization of genomic file formats, such as vcfs,
185+
bam, and bigbed files. pileup.js additionally allows flexible
186+
interaction with non-standard data formats. Users can visualize
187+
GA4GH JSON formatted alignments, features and variants. Users can
188+
also connect with and visualize data stored in GA4GH formatted data
189+
stores.
190+
"""
191+
),
192+
],
193+
),
194+
),
195+
],
196+
)
197+
],
198+
),
199+
dcc.Loading(
200+
parent_className="dashbio-loading",
201+
id="pileup-output",
202+
children=html.Div(
203+
[
204+
dash_bio.Pileup(
205+
id=_COMPONENT_ID,
206+
range=HOSTED_CASE_DICT["range"],
207+
reference=REFERENCE,
208+
tracks=HOSTED_CASE_DICT["celltype"],
209+
)
210+
]
211+
),
212+
),
213+
],
214+
)
215+
216+
217+
def callbacks(_app):
218+
HOSTED_CASE_DICT = rna_differential(_app)
219+
220+
@_app.callback(
221+
Output("pileup-dashbio-volcanoplot", "figure"),
222+
[Input("pileup-volcanoplot-input", "value")],
223+
)
224+
def update_volcano(effects):
225+
226+
return dash_bio.VolcanoPlot(
227+
dataframe=DE_dataframe,
228+
margin=go.layout.Margin(l=0, r=0, b=0),
229+
legend={"orientation": "h", "yanchor": "bottom", "y": 1.02, "x": 0.0,},
230+
effect_size="log2FoldChange",
231+
effect_size_line=effects,
232+
title="Differentially Expressed Genes",
233+
genomewideline_value=-np.log10(0.05),
234+
p="padj",
235+
snp="SNP",
236+
gene="Gene",
237+
)
238+
239+
@_app.callback(
240+
Output(_COMPONENT_ID, "range"), Input("pileup-dashbio-volcanoplot", "clickData")
241+
)
242+
def update_range(point):
243+
244+
if point is None:
245+
range = HOSTED_CASE_DICT["range"]
246+
else:
247+
248+
# get genomic location of selected genes and goto
249+
pointText = point["points"][0]["text"]
250+
gene = pointText.split("GENE: ")[-1]
251+
252+
row = DE_dataframe[DE_dataframe["Gene"] == gene].iloc[0]
253+
254+
range = {"contig": row["chr"], "start": row["start"], "stop": row["end"]}
255+
256+
return range
257+
258+
259+
app = run_standalone_app(layout, callbacks, header_colors, __file__)
260+
server = app.server
261+
262+
if __name__ == "__main__":
263+
app.run_server(debug=True, port=8050)
2.56 KB
Loading
2.28 KB
Loading

0 commit comments

Comments
 (0)