Merge branch '1637-improve-arv-tutorial'
[arvados.git] / doc / user / tutorial-trait-search.textile
1 ---
2 layout: default
3 navsection: userguide
4 title: "Tutorial: Search PGP data by trait"
5 navorder: 14
6 ---
7
8 h1. Tutorial: Search PGP data by trait
9
10 Here you will use the Python SDK to find public WGS data for people who have a certain medical condition.
11
12 <!-- _Define WGS_ -->
13
14 <!-- _Explain the motivation in this example a little better.  If I'm
15 reading this right, the workflow is 
16 traits -> people with those traits -> presense of a specific genetic
17 variant in the people with the reported traits_ -->
18
19 <!-- _Rather than having the user do this through the Python command line,
20 it might be easier to write a file that is going to do each step_ -->
21
22
23 h3. Prerequisites
24
25 * Log in to a VM "using SSH":ssh-access.html
26 * Put an "API token":api-tokens.html in your @ARVADOS_API_TOKEN@ environment variable
27 * Put the API host name in your @ARVADOS_API_HOST@ environment variable
28 * Run the @python@ interactive shell.
29
30 If everything is set up correctly, you will be able to import the arvados SDK:
31
32 <pre>
33 import arvados
34 </pre>
35
36 ...and display your account information:
37
38 <pre>
39 arvados.service.users().current().execute()
40 </pre>
41
42 h3. More prerequisites
43
44 <pre>
45 import re
46 import json
47 </pre>
48
49 h3. Find traits.
50
51 List traits containing the term "cancer":
52
53 <pre>
54 for t in filter(lambda t: re.search('cancer', t['name']),
55                 arvados.service.traits().list(limit=1000).execute()['items']):
56   print t['uuid'], t['name']
57
58 </pre>
59
60 <!-- _Should break this down into steps instead of being clever and making
61 it a python one-liner_ -->
62
63 %(darr)&darr;%
64
65 <pre>
66 ...
67 qr1hi-q1cn2-8q57g2diohwnzm0 Cervical cancer
68 qr1hi-q1cn2-vqp4243janpjbyj Breast cancer
69 qr1hi-q1cn2-v6usijujcpwqrn1 Non-melanoma skin cancer
70 ...
71 </pre>
72
73 We will use the "Non-melanoma skin cancer" trait with uuid @qr1hi-q1cn2-v6usijujcpwqrn1@.
74
75 <pre>
76 trait_uuid = 'qr1hi-q1cn2-v6usijujcpwqrn1'
77 </pre>
78
79 h3. Find humans.
80
81 List humans who report this condition:
82
83 <pre>
84 trait_links = arvados.service.links().list(limit=1000,where=json.dumps({
85     'link_class': 'human_trait',
86     'tail_kind': 'arvados#human',
87     'head_uuid': trait_uuid
88   })).execute()['items']
89 </pre>
90
91 <!-- _Same comment, break this out and describe each step_ -->
92
93 The "tail_uuid" attribute of each of these Links refers to a Human.
94
95 <pre>
96 map(lambda l: l['tail_uuid'], trait_links)
97 </pre>
98
99 %(darr)&darr;%
100
101 <pre>
102 [u'1h9kt-7a9it-c0uqa4kcdh29wdf', u'1h9kt-7a9it-x4tru6mn40hc6ah',
103 u'1h9kt-7a9it-yqb8m5s9cpy88i8', u'1h9kt-7a9it-46sm75w200ngwny',
104 u'1h9kt-7a9it-gx85a4tdkpzsg3w', u'1h9kt-7a9it-8cvlaa8909lgeo9',
105 u'1h9kt-7a9it-as37qum2pq8vizb', u'1h9kt-7a9it-14fph66z2baqxb9',
106 u'1h9kt-7a9it-e9zc7i4crmw3v69', u'1h9kt-7a9it-np7f35hlijlxdmt',
107 u'1h9kt-7a9it-j9hqyjwbvo9cojn', u'1h9kt-7a9it-lqxdtm1gynmsv13',
108 u'1h9kt-7a9it-zkhhxjfg2o22ywq', u'1h9kt-7a9it-nsjoxqd33lzldw9',
109 u'1h9kt-7a9it-ytect4smzcgd4kg', u'1h9kt-7a9it-y6tl353b3jc4tos',
110 u'1h9kt-7a9it-98f8qave4f8vbs5', u'1h9kt-7a9it-gd72sh15q0p4wq3',
111 u'1h9kt-7a9it-zlx25dscak94q9h', u'1h9kt-7a9it-8gronw4rbgmim01',
112 u'1h9kt-7a9it-wclfkjcb23tr5es', u'1h9kt-7a9it-rvp2qe7szfz4dy6',
113 u'1h9kt-7a9it-50iffhmpzsktwjm', u'1h9kt-7a9it-ul412id5y31a5o8',
114 u'1h9kt-7a9it-732kwkfzylmt4ik', u'1h9kt-7a9it-v9zqxegpblsbtai',
115 u'1h9kt-7a9it-kmaraqduit1v5wd', u'1h9kt-7a9it-t1nwtlo1hru5vvq',
116 u'1h9kt-7a9it-q3w6j9od4ibpoyl', u'1h9kt-7a9it-qz8vzkuuz97ezwv',
117 u'1h9kt-7a9it-t1v8sjz6dm9jmjf', u'1h9kt-7a9it-qe8wrbyvuqs5jew']
118 </pre>
119
120 h3. Find PGP IDs.
121
122 For now we don't need to look up the Human objects themselves.
123
124 As an aside, we will look up "identifier" links to find PGP-assigned participant identifiers:
125
126 <pre>
127 human_uuids = map(lambda l: l['tail_uuid'], trait_links)
128 pgpid_links = arvados.service.links().list(limit=1000,where=json.dumps({
129     "link_class": "identifier",
130     "head_uuid": human_uuids
131   })).execute()['items']
132 map(lambda l: l['name'], pgpid_links)
133 </pre>
134
135 %(darr)&darr;%
136
137 <pre>
138 [u'hu01024B', u'hu11603C', u'hu15402B', u'hu174334', u'hu1BD549', u'hu237A50',
139  u'hu34A921', u'hu397733', u'hu414115', u'hu43860C', u'hu474789', u'hu553620',
140  u'hu56B3B6', u'hu5917F3', u'hu599905', u'hu5E55F5', u'hu602487', u'hu633787',
141  u'hu68F245', u'hu6C3F34', u'hu7260DD', u'hu7A2F1D', u'hu94040B', u'hu9E356F',
142  u'huAB8707', u'huB1FD55', u'huB4883B', u'huD09050', u'huD09534', u'huD3A569',
143  u'huDF04CC', u'huE2E371']
144 </pre>
145
146 These PGP IDs let us find public profiles:
147
148 * "https://my.personalgenomes.org/profile/huE2E371":https://my.personalgenomes.org/profile/huE2E371
149 * "https://my.personalgenomes.org/profile/huDF04CC":https://my.personalgenomes.org/profile/huDF04CC
150 * ...
151
152 h3. Find data.
153
154 Find Collections that were provided by these Humans.
155
156 <pre>
157 provenance_links = arvados.service.links().list(where=json.dumps({
158     "link_class": "provenance",
159     "name": "provided",
160     "tail_uuid": human_uuids
161   })).execute()['items']
162 collection_uuids = map(lambda l: l['head_uuid'], provenance_links)
163
164 # build map of human uuid -> PGP ID
165 pgpid = {}
166 for pgpid_link in pgpid_links:
167   pgpid[pgpid_link['head_uuid']] = pgpid_link['name']
168
169 # build map of collection uuid -> PGP ID
170 for p_link in provenance_links:
171   pgpid[p_link['head_uuid']] = pgpid[p_link['tail_uuid']]
172
173 # get details (e.g., list of files) of each collection
174 collections = arvados.service.collections().list(where=json.dumps({
175     "uuid": collection_uuids
176   })).execute()['items']
177
178 # print PGP public profile links with file locators
179 for c in collections:
180   for f in c['files']:
181     print "https://my.personalgenomes.org/profile/%s %s %s%s" % (pgpid[c['uuid']], c['uuid'], ('' if f[0] == '.' else f[0]+'/'), f[1])
182
183 </pre>
184
185 %(darr)&darr;%
186
187 <pre>
188 https://my.personalgenomes.org/profile/hu43860C a58dca7609fa84c8c38a7e926a97b2fc+302+K@qr1hi var-GS00253-DNA_A01_200_37-ASM.tsv.bz2
189 https://my.personalgenomes.org/profile/huB1FD55 ea30eb9e46eedf7f05ed6e348c2baf5d+291+K@qr1hi var-GS000010320-ASM.tsv.bz2
190 https://my.personalgenomes.org/profile/huDF04CC 4ab0df8f22f595d1747a22c476c05873+242+K@qr1hi var-GS000010427-ASM.tsv.bz2
191 https://my.personalgenomes.org/profile/hu7A2F1D 756d0ada29b376140f64e7abfe6aa0e7+242+K@qr1hi var-GS000014566-ASM.tsv.bz2
192 https://my.personalgenomes.org/profile/hu553620 7ed4e425bb1c7cc18387cbd9388181df+242+K@qr1hi var-GS000015272-ASM.tsv.bz2
193 https://my.personalgenomes.org/profile/huD09534 542112e210daff30dd3cfea4801a9f2f+242+K@qr1hi var-GS000016374-ASM.tsv.bz2
194 https://my.personalgenomes.org/profile/hu599905 33a9f3842b01ea3fdf27cc582f5ea2af+242+K@qr1hi var-GS000016015-ASM.tsv.bz2
195 https://my.personalgenomes.org/profile/hu599905 d6e2e57cd60ba5979006d0b03e45e726+81+K@qr1hi Witch_results.zip
196 https://my.personalgenomes.org/profile/hu553620 ea4f2d325592a1272f989d141a917fdd+85+K@qr1hi Devenwood_results.zip
197 https://my.personalgenomes.org/profile/hu7A2F1D 4580f6620bb15b25b18373766e14e4a7+85+K@qr1hi Innkeeper_results.zip
198 https://my.personalgenomes.org/profile/huD09534 fee37be9440b912eb90f5e779f272416+82+K@qr1hi Hallet_results.zip
199 </pre>
200
201 h3. Search for a variant.
202
203 Look for variant rs1126809 in each of the "var" files (these contain variant calls from WGS data).
204
205 <pre>
206 job = {}
207 for c in collections:
208   if [] != filter(lambda f: re.search('^var-.*\.tsv\.bz2', f[1]), c['files']):
209     job[c['uuid']] = arvados.service.jobs().create(body={
210       'script': 'grep',
211       'script_parameters': {'input': c['uuid'], 'pattern': "rs1126809\\b"},
212       'script_version': 'e7aeb42'
213     }).execute()
214     print "%s %s" % (pgpid[c['uuid']], job[c['uuid']]['uuid'])
215
216 </pre>
217
218 &darr;
219
220 <pre>
221 hu43860C qr1hi-8i9sb-wyqq2eji4ehiwkq
222 huB1FD55 qr1hi-8i9sb-ep68uf0jkj3je7q
223 huDF04CC qr1hi-8i9sb-4ts4cvx6mbtcrsk
224 hu7A2F1D qr1hi-8i9sb-5lkiu9sh7vdgven
225 hu553620 qr1hi-8i9sb-nu4p6hjmziic022
226 huD09534 qr1hi-8i9sb-bt9389e9g3ff0m1
227 hu599905 qr1hi-8i9sb-ocg0i8r75luvke3
228 </pre>
229
230 Monitor job progress by refreshing the Jobs page in Workbench, or by using the API:
231
232 <pre>
233 map(lambda j: arvados.service.jobs().get(uuid=j['uuid']).execute()['success'], job.values())
234 </pre>
235
236 %(darr)&darr;%
237
238 <pre>
239 [True, True, True, True, True, True, True]
240 </pre>
241
242 (Unfinished jobs will appear as None, failed jobs as False, and completed jobs as True.)
243
244 After the jobs have completed, check output file sizes.
245
246 <pre>
247 for collection_uuid in job:
248   job_uuid = job[collection_uuid]['uuid']
249   job_output = arvados.service.jobs().get(uuid=job_uuid).execute()['output']
250   output_files = arvados.service.collections().get(uuid=job_output).execute()['files']
251   print "%s %3d %s" % (pgpid[collection_uuid], output_files[0][2], job_output)
252
253 </pre>
254
255 %(darr)&darr;%
256
257 <pre>
258 hu599905  80 5644238bfb2a1925d423f2c264819cfb+75+K@qr1hi
259 huD09534  80 f98f92573cf521333607910d320cc33b+75+K@qr1hi
260 huB1FD55   0 c10e07d8d90b51ee7f3b0a5855dc77c3+65+K@qr1hi
261 hu7A2F1D  80 922c4ce8d3dab3268edf8b9312cc63d4+75+K@qr1hi
262 hu553620   0 66da988f45a7ee16b6058fcbe9859d69+65+K@qr1hi
263 huDF04CC  80 bbe919451a437dde236a561d4e469ad2+75+K@qr1hi
264 hu43860C   0 45797e38410de9b9ddef2f4f0ec41a93+76+K@qr1hi
265 </pre>
266
267 Thus, of the 7 WGS results available for PGP participants reporting non-melanoma skin cancer, 4 include the rs1126809 / TYR-R402Q variant.