├── .gitignore ├── CONTRIBUTING.rst ├── LICENSE ├── README.md └── datalab └── genomics ├── Explore 1000 Genomes Samples.ipynb ├── FacetsDemo1000GenomesMetadata.ipynb ├── Genome-wide association study (GWAS).ipynb └── Getting started with the Genomics API.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | -------------------------------------------------------------------------------- /CONTRIBUTING.rst: -------------------------------------------------------------------------------- 1 | How to contribute 2 | =================================== 3 | 4 | First of all, thank you for contributing! 5 | 6 | The mailing list 7 | ---------------- 8 | 9 | For general questions or if you are having trouble getting started, try the 10 | `Google Genomics Discuss mailing list `_. 11 | It's a good way to sync up with other people who use googlegenomics including the core developers. You can subscribe 12 | by sending an email to ``google-genomics-discuss+subscribe@googlegroups.com`` or just post using 13 | the `web forum page `_. 14 | 15 | 16 | Submitting issues 17 | ----------------- 18 | 19 | If you are encountering a bug in the code or have a feature request in mind - file away! 20 | 21 | 22 | Submitting a pull request 23 | ------------------------- 24 | 25 | If you are ready to contribute code, Github provides a nice `overview on how to create a pull request 26 | `_. 27 | 28 | Some general rules to follow: 29 | 30 | * Do your work in `a fork `_ of this repo. 31 | * Create a branch for each update that you're working on. 32 | These branches are often called "feature" or "topic" branches. Any changes 33 | that you push to your feature branch will automatically be shown in the pull request. 34 | * Keep your pull requests as small as possible. Large pull requests are hard to review. 35 | Try to break up your changes into self-contained and incremental pull requests. 36 | * The first line of commit messages should be a short (<80 character) summary, 37 | followed by an empty line and then any details that you want to share about the commit. 38 | * Please try to follow the existing syntax style 39 | 40 | When you submit or change your pull request, the Travis build system will automatically run tests. 41 | If your pull request fails to pass tests, review the test log, make changes and 42 | then push them to your feature branch to be tested again. 43 | 44 | 45 | Contributor License Agreements 46 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 47 | 48 | All pull requests are welcome. Before we can submit them though, there is a legal hurdle we have to jump. 49 | You'll need to fill out either the individual or corporate Contributor License Agreement 50 | (CLA). 51 | 52 | * If you are an individual writing original source code and you're sure you 53 | own the intellectual property, then you'll need to sign an `individual CLA 54 | `_. 55 | * If you work for a company that wants to allow you to contribute your work, 56 | then you'll need to sign a `corporate CLA 57 | `_. 58 | 59 | Follow either of the two links above to access the appropriate CLA and 60 | instructions for how to sign and return it. Once we receive it, we'll be able to 61 | accept your pull requests. 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | datalab-examples 2 | =================== 3 | 4 | This repository contains example [Cloud Datalab](https://cloud.google.com/datalab/) Jupyter (formerly IPython) notebooks for genomics use cases upon public data such as the [Illumina Platinum Genomes](http://googlegenomics.readthedocs.org/en/latest/use_cases/discover_public_data/platinum_genomes.html) and [1,000 Genomes](http://googlegenomics.readthedocs.org/en/latest/use_cases/discover_public_data/1000_genomes.html). 5 | 6 | You can read them here on github: 7 | * [Exploring Genomic Data](https://github.com/googledatalab/notebooks/blob/master/samples/Exploring%20Genomics%20Data.ipynb) 8 | * [Explore the 1000 Genomes Sample Information](datalab/genomics/Explore%201000%20Genomes%20Samples.ipynb) 9 | * [Genome-wide association study](datalab/genomics/Genome-wide%20association%20study%20(GWAS).ipynb) 10 | * [Getting started with the Google Genomics API](datalab/genomics/Getting%20started%20with%20the%20Genomics%20API.ipynb) 11 | 12 | To run them yourself and discover other sample notebooks, see the [Google Genomics Cookbook](http://googlegenomics.readthedocs.org/en/latest/use_cases/run_familiar_tools/datalab.html). 13 | -------------------------------------------------------------------------------- /datalab/genomics/FacetsDemo1000GenomesMetadata.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "\n", 12 | "\n", 13 | "\n", 14 | "\n", 15 | "\n", 16 | "\n", 17 | "\n", 18 | "\n", 19 | "\n", 20 | "\n", 21 | "# Facets Demo on 1000 Genomes Metadata\n", 22 | "\n", 23 | "This notebook demonstrates using [Facets](https://pair-code.github.io/facets/) for nimble visualization of metadata from [1000 Genomes](https://cloud.google.com/genomics/data/1000-genomes). Facets contains two robust visualizations to get a sense of the shape of each feature of your dataset:\n", 24 | "\n", 25 | "* Facets Overview\n", 26 | "* Facets Dive\n", 27 | "\n", 28 | "Facets is from the [People+AI Research Initiative](https://ai.google/pair)." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "## Setup" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": null, 41 | "metadata": { 42 | "collapsed": false 43 | }, 44 | "outputs": [], 45 | "source": [ 46 | "FACETS_INSTALL_DIR = './'" 47 | ] 48 | }, 49 | { 50 | "cell_type": "code", 51 | "execution_count": null, 52 | "metadata": { 53 | "collapsed": false 54 | }, 55 | "outputs": [], 56 | "source": [ 57 | "%%bash -s \"$FACETS_INSTALL_DIR\"\n", 58 | "if [ ! -d \"${1}/facets\" ]; then\n", 59 | " # Install facets - only need to do this once per Datalab instance.\n", 60 | " cd $1\n", 61 | " git clone https://github.com/PAIR-code/facets\n", 62 | " cd facets\n", 63 | " jupyter nbextension install facets-dist/\n", 64 | "else\n", 65 | " echo Facets is already installed under $1.\n", 66 | "fi\n" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": null, 72 | "metadata": { 73 | "collapsed": false 74 | }, 75 | "outputs": [], 76 | "source": [ 77 | "# Add the facets overview python code to the python path and import dependencies.\n", 78 | "import os\n", 79 | "import sys\n", 80 | "sys.path.append(os.path.join(FACETS_INSTALL_DIR, 'facets/facets_overview/python'))\n", 81 | "reload(sys)\n", 82 | "sys.setdefaultencoding('utf-8')\n", 83 | "import pandas as pd\n", 84 | "import google.datalab.bigquery as bq\n", 85 | "from generic_feature_statistics_generator import GenericFeatureStatisticsGenerator\n", 86 | "from IPython.core.display import display, HTML\n", 87 | "import base64" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "## Retrieve the data" 95 | ] 96 | }, 97 | { 98 | "cell_type": "markdown", 99 | "metadata": {}, 100 | "source": [ 101 | "Here we define one query for an initial demo using metadata from [1000 Genomes](http://googlegenomics.readthedocs.io/en/latest/use_cases/discover_public_data/1000_genomes.html) but there are more queries at the bottom of this notebook.\n", 102 | "\n", 103 | "In general, as long as the query results in tabular-shaped data (e.g., you could export it to CSV) and it is on the order 10s of thousands of rows or less, it should work fine here. If larger than that, please sample the data before visualizing." 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": null, 109 | "metadata": { 110 | "collapsed": false 111 | }, 112 | "outputs": [], 113 | "source": [ 114 | "sql = \"\"\"\n", 115 | "--\n", 116 | "-- The 1000 Genomes metadata includes gender, familial relationships, population,\n", 117 | "-- super population, sequencing metrics, etc.\n", 118 | "--\n", 119 | "SELECT\n", 120 | " *\n", 121 | "FROM\n", 122 | " `genomics-public-data.1000_genomes.sample_info`\n", 123 | "\"\"\"" 124 | ] 125 | }, 126 | { 127 | "cell_type": "markdown", 128 | "metadata": {}, 129 | "source": [ 130 | "Execute the query to fill a Pandas dataframe with the data of interest.\n" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": null, 136 | "metadata": { 137 | "collapsed": false 138 | }, 139 | "outputs": [], 140 | "source": [ 141 | "query = bq.Query(sql)\n", 142 | "df = query.execute().result().to_dataframe()" 143 | ] 144 | }, 145 | { 146 | "cell_type": "markdown", 147 | "metadata": {}, 148 | "source": [ 149 | "## Visualize the result with Facets" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "The blocks of code that follow are boilerplate for visualizing the data using Facets Overview and Facets Dive. They use the value of variable `df` as the input to the visualization.\n", 157 | "\n", 158 | "Note: This interactive visualization requires javascript, so if this notebook is viewed from GitHub the output will be empty." 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "metadata": {}, 164 | "source": [ 165 | "### Facets Overview\n", 166 | "\n", 167 | "The following cell (when executed) will display the dataframe with Facets Overview." 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": null, 173 | "metadata": { 174 | "collapsed": false 175 | }, 176 | "outputs": [], 177 | "source": [ 178 | "proto = GenericFeatureStatisticsGenerator().ProtoFromDataFrames([{'name': 'test', 'table': df}])\n", 179 | "protostr = base64.b64encode(proto.SerializeToString()).decode(\"utf-8\")\n", 180 | "HTML_TEMPLATE = \"\"\"\n", 181 | "

Facets Overview of dataframe with shape {shape}

\n", 182 | " \n", 183 | " \"\"\"\n", 187 | "html = HTML_TEMPLATE.format(facetsPath=os.path.join(FACETS_INSTALL_DIR, 'facets/facets-dist/facets-jupyter.html'),\n", 188 | " shape=str(df.shape),\n", 189 | " protostr=protostr)\n", 190 | "display(HTML(html))" 191 | ] 192 | }, 193 | { 194 | "cell_type": "markdown", 195 | "metadata": {}, 196 | "source": [ 197 | "### Facets Dive\n", 198 | "\n", 199 | "The following cell (when executed) will display the dataframe with Facets Dive. For 1000 Genomes the default settings reproduce the last plot in [this notebook](https://github.com/googlegenomics/datalab-examples/blob/master/datalab/genomics/Explore%201000%20Genomes%20Samples.ipynb) to compare sequencing center metrcis. Zoom in to see more detail in each plot." 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": null, 205 | "metadata": { 206 | "collapsed": false 207 | }, 208 | "outputs": [], 209 | "source": [ 210 | "jsonstr = df.to_json(orient='records')\n", 211 | "HTML_TEMPLATE = \"\"\"\n", 212 | "

Facets Dive of dataframe with shape {shape}

\n", 213 | " \n", 214 | " \"\"\"\n", 227 | "html = HTML_TEMPLATE.format(facetsPath=os.path.join(FACETS_INSTALL_DIR, 'facets/facets-dist/facets-jupyter.html'),\n", 228 | " shape=str(df.shape),\n", 229 | " jsonstr=jsonstr)\n", 230 | "display(HTML(html))" 231 | ] 232 | }, 233 | { 234 | "cell_type": "markdown", 235 | "metadata": {}, 236 | "source": [ 237 | "# Additional Queries" 238 | ] 239 | }, 240 | { 241 | "cell_type": "markdown", 242 | "metadata": {}, 243 | "source": [ 244 | "Here are additional metadata queries for the [Personal Genome Project](http://googlegenomics.readthedocs.io/en/latest/use_cases/discover_public_data/pgp_public_data.html) and the [Simons Genome Diversity Project](http://googlegenomics.readthedocs.io/en/latest/use_cases/discover_public_data/simons_foundation.html).\n", 245 | "\n", 246 | "If you execute one of the following cells, it will update the `sql` variable. You can then return to the query and visualization cells above to re-execute them and display the new data." 247 | ] 248 | }, 249 | { 250 | "cell_type": "code", 251 | "execution_count": null, 252 | "metadata": { 253 | "collapsed": true 254 | }, 255 | "outputs": [], 256 | "source": [ 257 | "sql = \"\"\"\n", 258 | "--\n", 259 | "-- Examine metadata about individuals in the Personal Genomes Project.\n", 260 | "--\n", 261 | "SELECT * FROM `google.com:biggene.pgp.phenotypes` \n", 262 | "\"\"\"" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": { 269 | "collapsed": true 270 | }, 271 | "outputs": [], 272 | "source": [ 273 | "sql = \"\"\"\n", 274 | "--\n", 275 | "-- Examine metadata about individuals in the Simons Genome Diversity Project.\n", 276 | "--\n", 277 | "SELECT * \n", 278 | "FROM `genomics-public-data.simons_genome_diversity_project.sample_metadata` \n", 279 | "\"\"\"" 280 | ] 281 | } 282 | ], 283 | "metadata": { 284 | "kernelspec": { 285 | "display_name": "Python 2", 286 | "language": "python", 287 | "name": "python2" 288 | }, 289 | "language_info": { 290 | "codemirror_mode": { 291 | "name": "ipython", 292 | "version": 2 293 | }, 294 | "file_extension": ".py", 295 | "mimetype": "text/x-python", 296 | "name": "python", 297 | "nbconvert_exporter": "python", 298 | "pygments_lexer": "ipython2", 299 | "version": "2.7.12" 300 | } 301 | }, 302 | "nbformat": 4, 303 | "nbformat_minor": 2 304 | } 305 | -------------------------------------------------------------------------------- /datalab/genomics/Genome-wide association study (GWAS).ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "\n", 12 | "\n", 13 | "\n", 14 | "\n", 15 | "\n", 16 | "\n", 17 | "\n", 18 | "\n", 19 | "\n", 20 | "\n", 21 | "# Genome-wide association study (GWAS)" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "This notebook demonstrates conducting a genome-wide association study using the public 1000 Genomes dataset stored in BigQuery. Specifically we will:\n", 29 | "* Use the `%%sql` statement to write and execute SQL statements within the notebook\n", 30 | "* Extract data from BigQuery and create a local dataset that can be manipulated in Python for visualization and further analysis\n", 31 | "\n", 32 | "Related Links:\n", 33 | "* [BigQuery](https://cloud.google.com/bigquery/)\n", 34 | "* BigQuery [SQL reference](https://cloud.google.com/bigquery/query-reference)\n", 35 | "* [1,000 Genomes Data Description](http://googlegenomics.readthedocs.org/en/latest/use_cases/discover_public_data/1000_genomes.html)\n", 36 | "* This notebook is based on the [Google Genomics](https://cloud.google.com/genomics/) BigQuery examples:\n", 37 | " * [GWAS Chi-squared Test](https://github.com/googlegenomics/bigquery-examples/blob/master/1000genomes/sql/gwas-pattern-chi-squared-test.sql)\n", 38 | " * [GWAS z-test](https://github.com/googlegenomics/bigquery-examples/blob/master/1000genomes/sql/gwas-pattern-two-proportion-z-test.sql)\n", 39 | "\n", 40 | "----\n", 41 | "\n", 42 | "NOTE:\n", 43 | "\n", 44 | "* If you're new to notebooks, or want to check out additional samples, check out the full [list](../) of general notebooks.\n", 45 | "* For additional Genomics samples, check out the full [list](./) of Genomics notebooks." 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "## Experiment design" 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "In this experiment, we'll be identifying variant positions within chromosome 12 that differ significantly between the case and control groups. The case group for the purposes of this notebook will be individuals from the \"EAS\" (East Asian) super population. Variant data from the 1000 genomes dataset is publicly accessible within BigQuery. " 60 | ] 61 | }, 62 | { 63 | "cell_type": "code", 64 | "execution_count": 1, 65 | "metadata": { 66 | "collapsed": false 67 | }, 68 | "outputs": [ 69 | { 70 | "data": { 71 | "text/html": [ 72 | "\n", 73 | "
\n", 74 | " \n", 81 | " " 82 | ], 83 | "text/plain": [ 84 | "[{ 'name': 'reference_name', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'An identifier from the reference genome or an angle-bracketed ID String pointing to a contig in the assembly file.' },\n", 85 | " { 'name': 'start', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'The reference position, with the first base having position 0.' },\n", 86 | " { 'name': 'end', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 87 | " { 'name': 'reference_bases', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'Each base must be one of A,C,G,T,N (case insensitive). Multiple bases are permitted. The value in the POS field refers to the position of the first base in the String.' },\n", 88 | " { 'name': 'alternate_bases', 'type': 'STRING', 'mode':'REPEATED', 'description': 'List of alternate non-reference alleles called on at least one of the samples. (\"at least one\" not true for this dataset)' },\n", 89 | " { 'name': 'quality', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'phred-scaled quality score for the assertion made in ALT.' },\n", 90 | " { 'name': 'filter', 'type': 'STRING', 'mode':'REPEATED', 'description': 'PASS if this position has passed all filters, i.e. a call is made at this position. Otherwise, if the site has not passed all filters, a list of codes for filters that fail.' },\n", 91 | " { 'name': 'names', 'type': 'STRING', 'mode':'REPEATED', 'description': 'List of unique identifiers for the variant where available.' },\n", 92 | " { 'name': 'call', 'type': 'RECORD', 'mode':'REPEATED', 'description': 'Per-sample measurements.' },\n", 93 | " { 'name': 'call.call_set_id', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'The id of the callset from which this data was exported from the Google Genomics Variants API.' },\n", 94 | " { 'name': 'call.call_set_name', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'Sample identifier.' },\n", 95 | " { 'name': 'call.genotype', 'type': 'INTEGER', 'mode':'REPEATED', 'description': 'List of genotypes.' },\n", 96 | " { 'name': 'call.phaseset', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'If this value is null, the data is unphased. Otherwise it is phased.' },\n", 97 | " { 'name': 'call.genotype_likelihood', 'type': 'FLOAT', 'mode':'REPEATED', 'description': 'List of genotype likelihoods.' },\n", 98 | " { 'name': 'call.DP', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'FORMAT=' },\n", 99 | " { 'name': 'call.DS', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'FORMAT=' },\n", 100 | " { 'name': 'call.FT', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'None' },\n", 101 | " { 'name': 'call.GQ', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'FORMAT=' },\n", 102 | " { 'name': 'call.PL', 'type': 'INTEGER', 'mode':'REPEATED', 'description': 'FORMAT=' },\n", 103 | " { 'name': 'call.SP', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'FORMAT=' },\n", 104 | " { 'name': 'AA', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 105 | " { 'name': 'AC', 'type': 'INTEGER', 'mode':'REPEATED', 'description': 'INFO=' },\n", 106 | " { 'name': 'AC1', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 107 | " { 'name': 'AF', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 108 | " { 'name': 'AF1', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 109 | " { 'name': 'AFR_AF', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 110 | " { 'name': 'AMR_AF', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 111 | " { 'name': 'AN', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 112 | " { 'name': 'ASN_AF', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 113 | " { 'name': 'AVGPOST', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 114 | " { 'name': 'CIEND', 'type': 'INTEGER', 'mode':'REPEATED', 'description': 'INFO=' },\n", 115 | " { 'name': 'CIPOS', 'type': 'INTEGER', 'mode':'REPEATED', 'description': 'INFO=' },\n", 116 | " { 'name': 'DP', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 117 | " { 'name': 'DP4', 'type': 'INTEGER', 'mode':'REPEATED', 'description': 'INFO=' },\n", 118 | " { 'name': 'ERATE', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 119 | " { 'name': 'EUR_AF', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 120 | " { 'name': 'FQ', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 121 | " { 'name': 'G3', 'type': 'FLOAT', 'mode':'REPEATED', 'description': 'INFO=' },\n", 122 | " { 'name': 'HOMLEN', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 123 | " { 'name': 'HOMSEQ', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 124 | " { 'name': 'HWE', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 125 | " { 'name': 'LDAF', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 126 | " { 'name': 'MQ', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 127 | " { 'name': 'PV4', 'type': 'FLOAT', 'mode':'REPEATED', 'description': 'INFO=' },\n", 128 | " { 'name': 'RSQ', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 129 | " { 'name': 'SNPSOURCE', 'type': 'STRING', 'mode':'REPEATED', 'description': 'INFO=' },\n", 130 | " { 'name': 'SOURCE', 'type': 'STRING', 'mode':'REPEATED', 'description': '' },\n", 131 | " { 'name': 'SVLEN', 'type': 'INTEGER', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 132 | " { 'name': 'SVTYPE', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 133 | " { 'name': 'THETA', 'type': 'FLOAT', 'mode':'NULLABLE', 'description': 'INFO=' },\n", 134 | " { 'name': 'VT', 'type': 'STRING', 'mode':'NULLABLE', 'description': 'INFO=' }]" 135 | ] 136 | }, 137 | "execution_count": 1, 138 | "metadata": {}, 139 | "output_type": "execute_result" 140 | } 141 | ], 142 | "source": [ 143 | "import gcp.bigquery as bq\n", 144 | "variants_table = bq.Table('genomics-public-data:1000_genomes.variants')\n", 145 | "variants_table.schema" 146 | ] 147 | }, 148 | { 149 | "cell_type": "markdown", 150 | "metadata": {}, 151 | "source": [ 152 | "### Classifying per-call variant positions into variant/non-variant groups" 153 | ] 154 | }, 155 | { 156 | "cell_type": "markdown", 157 | "metadata": {}, 158 | "source": [ 159 | "We can tally the reference/alternate allele accounts for *individual* variant positions within chromosome 12. The field `call.genotype` is an integer ranging from `[-1, num_alternate_bases]`. \n", 160 | "* A value of negative one indicates that the genotype for the call is ambiguous (i.e., a no-call).\n", 161 | "* A value of zero indicates that the genotype for the call is the same as the reference (i.e., non-variant). \n", 162 | "* A value of one would indicate that the genotype for the call is the 1st value in the list of alternate bases (likewise for values >1)." 163 | ] 164 | }, 165 | { 166 | "cell_type": "code", 167 | "execution_count": 2, 168 | "metadata": { 169 | "collapsed": false 170 | }, 171 | "outputs": [], 172 | "source": [ 173 | "%%sql --module allele_counts\n", 174 | "\n", 175 | "SELECT \n", 176 | " reference_name,\n", 177 | " start,\n", 178 | " reference_bases,\n", 179 | " alternate_bases,\n", 180 | " end,\n", 181 | " vt, \n", 182 | " call.call_set_name AS call_set_name,\n", 183 | " # 1000 genomes phase 1 data is bi-allelic so there is only ever a single alt\n", 184 | " SUM(0 = call.genotype) WITHIN RECORD AS ref_count,\n", 185 | " SUM(1 = call.genotype) WITHIN RECORD AS alt_count,\n", 186 | "FROM\n", 187 | " FLATTEN((\n", 188 | " SELECT\n", 189 | " reference_name,\n", 190 | " start,\n", 191 | " reference_bases,\n", 192 | " alternate_bases,\n", 193 | " end,\n", 194 | " vt,\n", 195 | " call.call_set_name,\n", 196 | " call.genotype,\n", 197 | " FROM\n", 198 | " $variants_table\n", 199 | " WHERE\n", 200 | " reference_name = '12' -- i.e., chromosome 12\n", 201 | " ),\n", 202 | " call)" 203 | ] 204 | }, 205 | { 206 | "cell_type": "markdown", 207 | "metadata": {}, 208 | "source": [ 209 | "Let's verify that our allele counts match our expectations before moving on. For any given row, the alternate + reference counts should sum to 2 for this experiment." 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 3, 215 | "metadata": { 216 | "collapsed": false 217 | }, 218 | "outputs": [ 219 | { 220 | "data": { 221 | "text/html": [ 222 | "
\n", 223 | "\n", 224 | " \n", 225 | " \n", 226 | " \n", 227 | " \n", 228 | " \n", 229 | " \n", 230 | " \n", 231 | " \n", 232 | " \n", 233 | " \n", 234 | " \n", 235 | " \n", 236 | " \n", 237 | " \n", 238 | " \n", 239 | " \n", 240 | " \n", 241 | " \n", 242 | " \n", 243 | " \n", 244 | " \n", 245 | " \n", 246 | " \n", 247 | " \n", 248 | " \n", 249 | " \n", 250 | " \n", 251 | " \n", 252 | " \n", 253 | " \n", 254 | " \n", 255 | " \n", 256 | " \n", 257 | " \n", 258 | " \n", 259 | " \n", 260 | " \n", 261 | " \n", 262 | " \n", 263 | " \n", 264 | " \n", 265 | " \n", 266 | " \n", 267 | " \n", 268 | " \n", 269 | " \n", 270 | " \n", 271 | " \n", 272 | " \n", 273 | " \n", 274 | " \n", 275 | " \n", 276 | " \n", 277 | " \n", 278 | " \n", 279 | " \n", 280 | " \n", 281 | " \n", 282 | " \n", 283 | " \n", 284 | " \n", 285 | " \n", 286 | " \n", 287 | " \n", 288 | " \n", 289 | " \n", 290 | " \n", 291 | " \n", 292 | " \n", 293 | " \n", 294 | " \n", 295 | " \n", 296 | " \n", 297 | " \n", 298 | " \n", 299 | " \n", 300 | "
reference_namestartreference_basesalternate_basesendvtcall_set_nameref_countalt_count
01219434623AG19434624SNPHG0026120
11219434623AG19434624SNPHG0059320
21219434623AG19434624SNPNA1274920
31219434623AG19434624SNPHG0015020
41219434623AG19434624SNPNA1967520
\n", 301 | "
" 302 | ], 303 | "text/plain": [ 304 | " reference_name start reference_bases alternate_bases end vt \\\n", 305 | "0 12 19434623 A G 19434624 SNP \n", 306 | "1 12 19434623 A G 19434624 SNP \n", 307 | "2 12 19434623 A G 19434624 SNP \n", 308 | "3 12 19434623 A G 19434624 SNP \n", 309 | "4 12 19434623 A G 19434624 SNP \n", 310 | "\n", 311 | " call_set_name ref_count alt_count \n", 312 | "0 HG00261 2 0 \n", 313 | "1 HG00593 2 0 \n", 314 | "2 NA12749 2 0 \n", 315 | "3 HG00150 2 0 \n", 316 | "4 NA19675 2 0 " 317 | ] 318 | }, 319 | "execution_count": 3, 320 | "metadata": {}, 321 | "output_type": "execute_result" 322 | } 323 | ], 324 | "source": [ 325 | "bq.Query(allele_counts, variants_table=variants_table).sample().to_dataframe()" 326 | ] 327 | }, 328 | { 329 | "cell_type": "markdown", 330 | "metadata": {}, 331 | "source": [ 332 | "### Assigning case and control groups" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "metadata": {}, 338 | "source": [ 339 | "Now we can join our allele counts with metadata available in the sample info table. We'll use this sample metadata to split the set of genomes into case and control groups based upon the super population group." 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 4, 345 | "metadata": { 346 | "collapsed": false 347 | }, 348 | "outputs": [], 349 | "source": [ 350 | "sample_info_table = bq.Table('genomics-public-data:1000_genomes.sample_info')" 351 | ] 352 | }, 353 | { 354 | "cell_type": "code", 355 | "execution_count": 5, 356 | "metadata": { 357 | "collapsed": false 358 | }, 359 | "outputs": [], 360 | "source": [ 361 | "%%sql --module exp_groups\n", 362 | "\n", 363 | "SELECT\n", 364 | " super_population,\n", 365 | " ('EAS' = super_population) AS is_case,\n", 366 | " call_set_name,\n", 367 | " reference_name,\n", 368 | " start,\n", 369 | " reference_bases,\n", 370 | " alternate_bases,\n", 371 | " end,\n", 372 | " vt,\n", 373 | " ref_count,\n", 374 | " alt_count,\n", 375 | "FROM $allele_counts AS allele_counts\n", 376 | "JOIN $sample_info_table AS samples\n", 377 | " ON allele_counts.call_set_name = samples.sample" 378 | ] 379 | }, 380 | { 381 | "cell_type": "code", 382 | "execution_count": 6, 383 | "metadata": { 384 | "collapsed": false 385 | }, 386 | "outputs": [ 387 | { 388 | "data": { 389 | "text/html": [ 390 | "
\n", 391 | "\n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | "
super_populationis_casecall_set_namereference_namestartreference_basesalternate_basesendvtref_countalt_count
0EURFalseHG002611218330083CA18330084SNP02
1EASTrueHG005931218330083CA18330084SNP11
2EURFalseNA127491218330083CA18330084SNP02
3EURFalseHG001501218330083CA18330084SNP11
4AMRFalseNA196751218330083CA18330084SNP02
\n", 481 | "
" 482 | ], 483 | "text/plain": [ 484 | " super_population is_case call_set_name reference_name start \\\n", 485 | "0 EUR False HG00261 12 18330083 \n", 486 | "1 EAS True HG00593 12 18330083 \n", 487 | "2 EUR False NA12749 12 18330083 \n", 488 | "3 EUR False HG00150 12 18330083 \n", 489 | "4 AMR False NA19675 12 18330083 \n", 490 | "\n", 491 | " reference_bases alternate_bases end vt ref_count alt_count \n", 492 | "0 C A 18330084 SNP 0 2 \n", 493 | "1 C A 18330084 SNP 1 1 \n", 494 | "2 C A 18330084 SNP 0 2 \n", 495 | "3 C A 18330084 SNP 1 1 \n", 496 | "4 C A 18330084 SNP 0 2 " 497 | ] 498 | }, 499 | "execution_count": 6, 500 | "metadata": {}, 501 | "output_type": "execute_result" 502 | } 503 | ], 504 | "source": [ 505 | "bq.Query(exp_groups, allele_counts=allele_counts,\n", 506 | " sample_info_table=sample_info_table,\n", 507 | " variants_table=variants_table).sample().to_dataframe()" 508 | ] 509 | }, 510 | { 511 | "cell_type": "markdown", 512 | "metadata": {}, 513 | "source": [ 514 | "The variants table contains a few different types of variant: structural variants (\"SV\"), indels (\"INDEL\") and SNPs (\"SNP\")." 515 | ] 516 | }, 517 | { 518 | "cell_type": "code", 519 | "execution_count": 7, 520 | "metadata": { 521 | "collapsed": false 522 | }, 523 | "outputs": [ 524 | { 525 | "data": { 526 | "text/html": [ 527 | "\n", 528 | "
\n", 529 | "
(rows: 3, time: 0.4s, cached, job: job_l3Z5dkMGEBkpl61jsNfJu6-GXmg)
\n", 530 | " \n", 544 | " " 545 | ], 546 | "text/plain": [] 547 | }, 548 | "execution_count": 7, 549 | "metadata": {}, 550 | "output_type": "execute_result" 551 | } 552 | ], 553 | "source": [ 554 | "%%sql\n", 555 | "SELECT \n", 556 | " vt,\n", 557 | " COUNT(*)\n", 558 | "FROM $exp_groups\n", 559 | "GROUP BY vt" 560 | ] 561 | }, 562 | { 563 | "cell_type": "markdown", 564 | "metadata": {}, 565 | "source": [ 566 | "For the purposes of this experiment, let's limit the variants to only SNPs." 567 | ] 568 | }, 569 | { 570 | "cell_type": "code", 571 | "execution_count": 8, 572 | "metadata": { 573 | "collapsed": false 574 | }, 575 | "outputs": [], 576 | "source": [ 577 | "%%sql --module snps\n", 578 | "SELECT * \n", 579 | "FROM $exp_groups\n", 580 | "WHERE vt='SNP'" 581 | ] 582 | }, 583 | { 584 | "cell_type": "code", 585 | "execution_count": 9, 586 | "metadata": { 587 | "collapsed": false 588 | }, 589 | "outputs": [ 590 | { 591 | "data": { 592 | "text/html": [ 593 | "
\n", 594 | "\n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | " \n", 603 | " \n", 604 | " \n", 605 | " \n", 606 | " \n", 607 | " \n", 608 | " \n", 609 | " \n", 610 | " \n", 611 | " \n", 612 | " \n", 613 | " \n", 614 | " \n", 615 | " \n", 616 | " \n", 617 | " \n", 618 | " \n", 619 | " \n", 620 | " \n", 621 | " \n", 622 | " \n", 623 | " \n", 624 | " \n", 625 | " \n", 626 | " \n", 627 | " \n", 628 | " \n", 629 | " \n", 630 | " \n", 631 | " \n", 632 | " \n", 633 | " \n", 634 | " \n", 635 | " \n", 636 | " \n", 637 | " \n", 638 | " \n", 639 | " \n", 640 | " \n", 641 | " \n", 642 | " \n", 643 | " \n", 644 | " \n", 645 | " \n", 646 | " \n", 647 | " \n", 648 | " \n", 649 | " \n", 650 | " \n", 651 | " \n", 652 | " \n", 653 | " \n", 654 | " \n", 655 | " \n", 656 | " \n", 657 | " \n", 658 | " \n", 659 | " \n", 660 | " \n", 661 | " \n", 662 | " \n", 663 | " \n", 664 | " \n", 665 | " \n", 666 | " \n", 667 | " \n", 668 | " \n", 669 | " \n", 670 | " \n", 671 | " \n", 672 | " \n", 673 | " \n", 674 | " \n", 675 | " \n", 676 | " \n", 677 | " \n", 678 | " \n", 679 | " \n", 680 | " \n", 681 | " \n", 682 | " \n", 683 | "
super_populationis_casecall_set_namereference_namestartreference_basesalternate_basesendvtref_countalt_count
0EURFalseHG002611218372942AG18372943SNP20
1EASTrueHG005931218372942AG18372943SNP20
2EURFalseNA127491218372942AG18372943SNP20
3EURFalseHG001501218372942AG18372943SNP20
4AMRFalseNA196751218372942AG18372943SNP20
\n", 684 | "
" 685 | ], 686 | "text/plain": [ 687 | " super_population is_case call_set_name reference_name start \\\n", 688 | "0 EUR False HG00261 12 18372942 \n", 689 | "1 EAS True HG00593 12 18372942 \n", 690 | "2 EUR False NA12749 12 18372942 \n", 691 | "3 EUR False HG00150 12 18372942 \n", 692 | "4 AMR False NA19675 12 18372942 \n", 693 | "\n", 694 | " reference_bases alternate_bases end vt ref_count alt_count \n", 695 | "0 A G 18372943 SNP 2 0 \n", 696 | "1 A G 18372943 SNP 2 0 \n", 697 | "2 A G 18372943 SNP 2 0 \n", 698 | "3 A G 18372943 SNP 2 0 \n", 699 | "4 A G 18372943 SNP 2 0 " 700 | ] 701 | }, 702 | "execution_count": 9, 703 | "metadata": {}, 704 | "output_type": "execute_result" 705 | } 706 | ], 707 | "source": [ 708 | "bq.Query(snps,\n", 709 | " exp_groups=exp_groups,\n", 710 | " allele_counts=allele_counts,\n", 711 | " sample_info_table=sample_info_table,\n", 712 | " variants_table=variants_table).sample().to_dataframe()" 713 | ] 714 | }, 715 | { 716 | "cell_type": "markdown", 717 | "metadata": {}, 718 | "source": [ 719 | "### Tallying reference/alternate allele counts for case/control groups" 720 | ] 721 | }, 722 | { 723 | "cell_type": "markdown", 724 | "metadata": {}, 725 | "source": [ 726 | "Now that we've assigned each call set to either the case or the control group, we can tally up the counts of reference and alternate alleles within each of our assigned case/control groups, for each variant position, like so:" 727 | ] 728 | }, 729 | { 730 | "cell_type": "code", 731 | "execution_count": 10, 732 | "metadata": { 733 | "collapsed": false 734 | }, 735 | "outputs": [], 736 | "source": [ 737 | "%%sql --module grouped_counts\n", 738 | "\n", 739 | "SELECT\n", 740 | " reference_name,\n", 741 | " start,\n", 742 | " end,\n", 743 | " reference_bases,\n", 744 | " alternate_bases,\n", 745 | " vt,\n", 746 | " SUM(ref_count + alt_count) AS allele_count,\n", 747 | " SUM(ref_count) AS ref_count,\n", 748 | " SUM(alt_count) AS alt_count,\n", 749 | " SUM(IF(TRUE = is_case, INTEGER(ref_count + alt_count), 0)) AS case_count,\n", 750 | " SUM(IF(FALSE = is_case, INTEGER(ref_count + alt_count), 0)) AS control_count,\n", 751 | " SUM(IF(TRUE = is_case, ref_count, 0)) AS case_ref_count,\n", 752 | " SUM(IF(TRUE = is_case, alt_count, 0)) AS case_alt_count,\n", 753 | " SUM(IF(FALSE = is_case, ref_count, 0)) AS control_ref_count,\n", 754 | " SUM(IF(FALSE = is_case, alt_count, 0)) AS control_alt_count,\n", 755 | "FROM $snps\n", 756 | "GROUP BY\n", 757 | " reference_name,\n", 758 | " start,\n", 759 | " end,\n", 760 | " reference_bases,\n", 761 | " alternate_bases,\n", 762 | " vt" 763 | ] 764 | }, 765 | { 766 | "cell_type": "markdown", 767 | "metadata": {}, 768 | "source": [ 769 | "Again, validate that the results are sensical for the group level counts (still per variant position)." 770 | ] 771 | }, 772 | { 773 | "cell_type": "code", 774 | "execution_count": 11, 775 | "metadata": { 776 | "collapsed": false 777 | }, 778 | "outputs": [ 779 | { 780 | "data": { 781 | "text/html": [ 782 | "
\n", 783 | "\n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | " \n", 830 | " \n", 831 | " \n", 832 | " \n", 833 | " \n", 834 | " \n", 835 | " \n", 836 | " \n", 837 | " \n", 838 | " \n", 839 | " \n", 840 | " \n", 841 | " \n", 842 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 846 | " \n", 847 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 851 | " \n", 852 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 856 | " \n", 857 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 862 | " \n", 863 | " \n", 864 | " \n", 865 | " \n", 866 | " \n", 867 | " \n", 868 | " \n", 869 | " \n", 870 | " \n", 871 | " \n", 872 | " \n", 873 | " \n", 874 | " \n", 875 | " \n", 876 | " \n", 877 | " \n", 878 | " \n", 879 | " \n", 880 | " \n", 881 | " \n", 882 | " \n", 883 | " \n", 884 | " \n", 885 | " \n", 886 | " \n", 887 | " \n", 888 | " \n", 889 | " \n", 890 | " \n", 891 | " \n", 892 | " \n", 893 | " \n", 894 | " \n", 895 | " \n", 896 | "
reference_namestartendreference_basesalternate_basesvtallele_countref_countalt_countcase_countcontrol_countcase_ref_countcase_alt_countcontrol_ref_countcontrol_alt_count
012113369176113369177TGSNP2184499168557216121244483751237
1128411709084117091TASNP2184218225721612572016102
2124172941841729419GASNP2184110110835721612283289818794
3124176811041768111GASNP2184112110635721612284288837775
4122658434526584346GASNP21841032081572161205721031509
\n", 897 | "
" 898 | ], 899 | "text/plain": [ 900 | " reference_name start end reference_bases alternate_bases vt \\\n", 901 | "0 12 113369176 113369177 T G SNP \n", 902 | "1 12 84117090 84117091 T A SNP \n", 903 | "2 12 41729418 41729419 G A SNP \n", 904 | "3 12 41768110 41768111 G A SNP \n", 905 | "4 12 26584345 26584346 G A SNP \n", 906 | "\n", 907 | " allele_count ref_count alt_count case_count control_count \\\n", 908 | "0 2184 499 1685 572 1612 \n", 909 | "1 2184 2182 2 572 1612 \n", 910 | "2 2184 1101 1083 572 1612 \n", 911 | "3 2184 1121 1063 572 1612 \n", 912 | "4 2184 103 2081 572 1612 \n", 913 | "\n", 914 | " case_ref_count case_alt_count control_ref_count control_alt_count \n", 915 | "0 124 448 375 1237 \n", 916 | "1 572 0 1610 2 \n", 917 | "2 283 289 818 794 \n", 918 | "3 284 288 837 775 \n", 919 | "4 0 572 103 1509 " 920 | ] 921 | }, 922 | "execution_count": 11, 923 | "metadata": {}, 924 | "output_type": "execute_result" 925 | } 926 | ], 927 | "source": [ 928 | "bq.Query(grouped_counts,\n", 929 | " snps=snps,\n", 930 | " exp_groups=exp_groups,\n", 931 | " allele_counts=allele_counts,\n", 932 | " sample_info_table=sample_info_table,\n", 933 | " variants_table=variants_table).sample().to_dataframe()" 934 | ] 935 | }, 936 | { 937 | "cell_type": "markdown", 938 | "metadata": {}, 939 | "source": [ 940 | "## Quantify the statistical significance at each variant positions" 941 | ] 942 | }, 943 | { 944 | "cell_type": "markdown", 945 | "metadata": {}, 946 | "source": [ 947 | "We can quantify the statistical significance of each variant position using the Chi-squared test. Furthermore, we can restrict our result set to *only* statistically significant variant positions for this experiment by ranking each position by its statistical signficance (decreasing) and thresholding the results for significance at `p <= 5e-8` (chi-squared score >= 29.7)." 948 | ] 949 | }, 950 | { 951 | "cell_type": "code", 952 | "execution_count": 12, 953 | "metadata": { 954 | "collapsed": false 955 | }, 956 | "outputs": [], 957 | "source": [ 958 | "%%sql --module results\n", 959 | "\n", 960 | "SELECT\n", 961 | " reference_name,\n", 962 | " start,\n", 963 | " end,\n", 964 | " reference_bases,\n", 965 | " alternate_bases,\n", 966 | " vt,\n", 967 | " case_count,\n", 968 | " control_count,\n", 969 | " allele_count,\n", 970 | " ref_count,\n", 971 | " alt_count,\n", 972 | " case_ref_count,\n", 973 | " case_alt_count,\n", 974 | " control_ref_count,\n", 975 | " control_alt_count,\n", 976 | " # http://homes.cs.washington.edu/~suinlee/genome560/lecture7.pdf\n", 977 | " # https://en.wikipedia.org/wiki/Yates%27s_correction_for_continuity\n", 978 | " ROUND(\n", 979 | " POW(ABS(case_ref_count - (ref_count/allele_count)*case_count) - 0.5,\n", 980 | " 2)/((ref_count/allele_count)*case_count) +\n", 981 | " POW(ABS(control_ref_count - (ref_count/allele_count)*control_count) - 0.5,\n", 982 | " 2)/((ref_count/allele_count)*control_count) +\n", 983 | " POW(ABS(case_alt_count - (alt_count/allele_count)*case_count) - 0.5,\n", 984 | " 2)/((alt_count/allele_count)*case_count) +\n", 985 | " POW(ABS(control_alt_count - (alt_count/allele_count)*control_count) - 0.5,\n", 986 | " 2)/((alt_count/allele_count)*control_count),\n", 987 | " 3) AS chi_squared_score\n", 988 | "FROM $grouped_counts\n", 989 | "WHERE\n", 990 | " # For chi-squared, expected counts must be at least 5 for each group\n", 991 | " (ref_count/allele_count)*case_count >= 5.0\n", 992 | " AND (ref_count/allele_count)*control_count >= 5.0\n", 993 | " AND (alt_count/allele_count)*case_count >= 5.0\n", 994 | " AND (alt_count/allele_count)*control_count >= 5.0\n", 995 | "HAVING\n", 996 | " # Chi-squared critical value for df=1, p-value=5*10^-8 is 29.71679\n", 997 | " chi_squared_score >= 29.71679\n", 998 | "ORDER BY\n", 999 | " chi_squared_score DESC,\n", 1000 | " allele_count DESC" 1001 | ] 1002 | }, 1003 | { 1004 | "cell_type": "markdown", 1005 | "metadata": {}, 1006 | "source": [ 1007 | "We now run this query over **all** the variants within chromosome 12 and return the first few most significant variants." 1008 | ] 1009 | }, 1010 | { 1011 | "cell_type": "code", 1012 | "execution_count": 13, 1013 | "metadata": { 1014 | "collapsed": false 1015 | }, 1016 | "outputs": [ 1017 | { 1018 | "data": { 1019 | "text/html": [ 1020 | "
\n", 1021 | "\n", 1022 | " \n", 1023 | " \n", 1024 | " \n", 1025 | " \n", 1026 | " \n", 1027 | " \n", 1028 | " \n", 1029 | " \n", 1030 | " \n", 1031 | " \n", 1032 | " \n", 1033 | " \n", 1034 | " \n", 1035 | " \n", 1036 | " \n", 1037 | " \n", 1038 | " \n", 1039 | " \n", 1040 | " \n", 1041 | " \n", 1042 | " \n", 1043 | " \n", 1044 | " \n", 1045 | " \n", 1046 | " \n", 1047 | " \n", 1048 | " \n", 1049 | " \n", 1050 | " \n", 1051 | " \n", 1052 | " \n", 1053 | " \n", 1054 | " \n", 1055 | " \n", 1056 | " \n", 1057 | " \n", 1058 | " \n", 1059 | " \n", 1060 | " \n", 1061 | " \n", 1062 | " \n", 1063 | " \n", 1064 | " \n", 1065 | " \n", 1066 | " \n", 1067 | " \n", 1068 | " \n", 1069 | " \n", 1070 | " \n", 1071 | " \n", 1072 | " \n", 1073 | " \n", 1074 | " \n", 1075 | " \n", 1076 | " \n", 1077 | " \n", 1078 | " \n", 1079 | " \n", 1080 | " \n", 1081 | " \n", 1082 | " \n", 1083 | " \n", 1084 | " \n", 1085 | " \n", 1086 | " \n", 1087 | " \n", 1088 | " \n", 1089 | " \n", 1090 | " \n", 1091 | " \n", 1092 | " \n", 1093 | " \n", 1094 | " \n", 1095 | " \n", 1096 | " \n", 1097 | " \n", 1098 | " \n", 1099 | " \n", 1100 | " \n", 1101 | " \n", 1102 | " \n", 1103 | " \n", 1104 | " \n", 1105 | " \n", 1106 | " \n", 1107 | " \n", 1108 | " \n", 1109 | " \n", 1110 | " \n", 1111 | " \n", 1112 | " \n", 1113 | " \n", 1114 | " \n", 1115 | " \n", 1116 | " \n", 1117 | " \n", 1118 | " \n", 1119 | " \n", 1120 | " \n", 1121 | " \n", 1122 | " \n", 1123 | " \n", 1124 | " \n", 1125 | " \n", 1126 | " \n", 1127 | " \n", 1128 | " \n", 1129 | " \n", 1130 | " \n", 1131 | " \n", 1132 | " \n", 1133 | " \n", 1134 | " \n", 1135 | " \n", 1136 | " \n", 1137 | " \n", 1138 | " \n", 1139 | " \n", 1140 | "
reference_namestartendreference_basesalternate_basesvtcase_countcontrol_countallele_countref_countalt_countcase_ref_countcase_alt_countcontrol_ref_countcontrol_alt_countchi_squared_score
012110571373110571374AGSNP5721612218418133712203521593191086.505
1122250909422509095TCSNP57216122184158959511645614731391073.082
2122252535222525353ACSNP57216122184158559911545714701421068.266
3122252424022524241TCSNP57216122184158460011545714691431065.294
4123324056733240568CGSNP5721612218416785061594131519931043.029
\n", 1141 | "
" 1142 | ], 1143 | "text/plain": [ 1144 | " reference_name start end reference_bases alternate_bases vt \\\n", 1145 | "0 12 110571373 110571374 A G SNP \n", 1146 | "1 12 22509094 22509095 T C SNP \n", 1147 | "2 12 22525352 22525353 A C SNP \n", 1148 | "3 12 22524240 22524241 T C SNP \n", 1149 | "4 12 33240567 33240568 C G SNP \n", 1150 | "\n", 1151 | " case_count control_count allele_count ref_count alt_count \\\n", 1152 | "0 572 1612 2184 1813 371 \n", 1153 | "1 572 1612 2184 1589 595 \n", 1154 | "2 572 1612 2184 1585 599 \n", 1155 | "3 572 1612 2184 1584 600 \n", 1156 | "4 572 1612 2184 1678 506 \n", 1157 | "\n", 1158 | " case_ref_count case_alt_count control_ref_count control_alt_count \\\n", 1159 | "0 220 352 1593 19 \n", 1160 | "1 116 456 1473 139 \n", 1161 | "2 115 457 1470 142 \n", 1162 | "3 115 457 1469 143 \n", 1163 | "4 159 413 1519 93 \n", 1164 | "\n", 1165 | " chi_squared_score \n", 1166 | "0 1086.505 \n", 1167 | "1 1073.082 \n", 1168 | "2 1068.266 \n", 1169 | "3 1065.294 \n", 1170 | "4 1043.029 " 1171 | ] 1172 | }, 1173 | "execution_count": 13, 1174 | "metadata": {}, 1175 | "output_type": "execute_result" 1176 | } 1177 | ], 1178 | "source": [ 1179 | "bq.Query(results,\n", 1180 | " grouped_counts=grouped_counts,\n", 1181 | " snps=snps,\n", 1182 | " exp_groups=exp_groups,\n", 1183 | " allele_counts=allele_counts,\n", 1184 | " sample_info_table=sample_info_table,\n", 1185 | " variants_table=variants_table).sample().to_dataframe()" 1186 | ] 1187 | }, 1188 | { 1189 | "cell_type": "markdown", 1190 | "metadata": {}, 1191 | "source": [ 1192 | "Scroll to the right in the above results to see that the positions deemed significant do in fact have significantly different case/control counts for the alternate/reference bases." 1193 | ] 1194 | }, 1195 | { 1196 | "cell_type": "markdown", 1197 | "metadata": {}, 1198 | "source": [ 1199 | "### Computing Chi-squared statistics in BigQuery vs Python vs R" 1200 | ] 1201 | }, 1202 | { 1203 | "cell_type": "markdown", 1204 | "metadata": {}, 1205 | "source": [ 1206 | "Let's compare these BigQuery-computed Chi-squared scores to ones calculated via Python's statistical packages" 1207 | ] 1208 | }, 1209 | { 1210 | "cell_type": "code", 1211 | "execution_count": 14, 1212 | "metadata": { 1213 | "collapsed": false 1214 | }, 1215 | "outputs": [ 1216 | { 1217 | "name": "stdout", 1218 | "output_type": "stream", 1219 | "text": [ 1220 | "Python Chi-sq score = 1086.505\n" 1221 | ] 1222 | } 1223 | ], 1224 | "source": [ 1225 | "import numpy as np\n", 1226 | "from scipy.stats import chi2_contingency\n", 1227 | "\n", 1228 | "chi2, p, dof, expected = chi2_contingency(np.array([ \n", 1229 | " [220, 352], # case \n", 1230 | " [1593, 19] # control\n", 1231 | "]))\n", 1232 | "\n", 1233 | "print 'Python Chi-sq score = %.3f' % chi2" 1234 | ] 1235 | }, 1236 | { 1237 | "cell_type": "markdown", 1238 | "metadata": {}, 1239 | "source": [ 1240 | "Comparing Python statistics to those computed in R separately with the result displayed here:\n", 1241 | "```\n", 1242 | "> chisq.test(rbind(c(220, 352), c(1593, 19)))\n", 1243 | "\n", 1244 | "\tPearson's Chi-squared test with Yates' continuity correction\n", 1245 | "\n", 1246 | "data: rbind(c(220, 352), c(1593, 19))\n", 1247 | "X-squared = 1086.505, df = 1, p-value < 2.2e-16\n", 1248 | "```" 1249 | ] 1250 | }, 1251 | { 1252 | "cell_type": "markdown", 1253 | "metadata": {}, 1254 | "source": [ 1255 | "And we can see for both the computation in Python and R, that the value matches 1086.505 from BigQuery." 1256 | ] 1257 | }, 1258 | { 1259 | "cell_type": "markdown", 1260 | "metadata": {}, 1261 | "source": [ 1262 | "## Analyzing the GWAS results" 1263 | ] 1264 | }, 1265 | { 1266 | "cell_type": "markdown", 1267 | "metadata": {}, 1268 | "source": [ 1269 | "First, how many statistically significant variant positions did we find?" 1270 | ] 1271 | }, 1272 | { 1273 | "cell_type": "code", 1274 | "execution_count": 15, 1275 | "metadata": { 1276 | "collapsed": false 1277 | }, 1278 | "outputs": [ 1279 | { 1280 | "data": { 1281 | "text/html": [ 1282 | "\n", 1283 | "
\n", 1284 | "
(rows: 1, time: 0.5s, cached, job: job_LrwWjBy-rCHAGBsE2LpCikoKclA)
\n", 1285 | " \n", 1299 | " " 1300 | ], 1301 | "text/plain": [] 1302 | }, 1303 | "execution_count": 15, 1304 | "metadata": {}, 1305 | "output_type": "execute_result" 1306 | } 1307 | ], 1308 | "source": [ 1309 | "%%sql \n", 1310 | "SELECT COUNT(*) AS num_significant_snps\n", 1311 | "FROM $results" 1312 | ] 1313 | }, 1314 | { 1315 | "cell_type": "markdown", 1316 | "metadata": {}, 1317 | "source": [ 1318 | "We now have a dataset that is sufficiently small to fit into memory on our instance, so let's pull the top 1000 SNP positions locally. Since we only need a subset of the columns, we can project our data first to remove unneeded columns." 1319 | ] 1320 | }, 1321 | { 1322 | "cell_type": "code", 1323 | "execution_count": 16, 1324 | "metadata": { 1325 | "collapsed": false 1326 | }, 1327 | "outputs": [], 1328 | "source": [ 1329 | "%%sql --module sig_snps_dataset\n", 1330 | "SELECT * FROM (\n", 1331 | " SELECT\n", 1332 | " reference_name,\n", 1333 | " start,\n", 1334 | " reference_bases,\n", 1335 | " alternate_bases,\n", 1336 | " chi_squared_score\n", 1337 | " FROM $results\n", 1338 | " LIMIT 1000\n", 1339 | ")\n", 1340 | "ORDER BY start asc" 1341 | ] 1342 | }, 1343 | { 1344 | "cell_type": "code", 1345 | "execution_count": 17, 1346 | "metadata": { 1347 | "collapsed": false 1348 | }, 1349 | "outputs": [ 1350 | { 1351 | "data": { 1352 | "text/html": [ 1353 | "
\n", 1354 | "\n", 1355 | " \n", 1356 | " \n", 1357 | " \n", 1358 | " \n", 1359 | " \n", 1360 | " \n", 1361 | " \n", 1362 | " \n", 1363 | " \n", 1364 | " \n", 1365 | " \n", 1366 | " \n", 1367 | " \n", 1368 | " \n", 1369 | " \n", 1370 | " \n", 1371 | " \n", 1372 | " \n", 1373 | " \n", 1374 | " \n", 1375 | " \n", 1376 | " \n", 1377 | " \n", 1378 | " \n", 1379 | " \n", 1380 | " \n", 1381 | " \n", 1382 | " \n", 1383 | " \n", 1384 | " \n", 1385 | " \n", 1386 | " \n", 1387 | " \n", 1388 | " \n", 1389 | " \n", 1390 | " \n", 1391 | " \n", 1392 | " \n", 1393 | " \n", 1394 | " \n", 1395 | " \n", 1396 | " \n", 1397 | " \n", 1398 | " \n", 1399 | " \n", 1400 | " \n", 1401 | " \n", 1402 | " \n", 1403 | " \n", 1404 | " \n", 1405 | " \n", 1406 | " \n", 1407 | " \n", 1408 | " \n", 1409 | " \n", 1410 | " \n", 1411 | " \n", 1412 | " \n", 1413 | " \n", 1414 | " \n", 1415 | " \n", 1416 | " \n", 1417 | " \n", 1418 | " \n", 1419 | " \n", 1420 | " \n", 1421 | " \n", 1422 | " \n", 1423 | " \n", 1424 | " \n", 1425 | " \n", 1426 | " \n", 1427 | " \n", 1428 | " \n", 1429 | " \n", 1430 | " \n", 1431 | " \n", 1432 | " \n", 1433 | " \n", 1434 | " \n", 1435 | " \n", 1436 | " \n", 1437 | " \n", 1438 | " \n", 1439 | " \n", 1440 | " \n", 1441 | " \n", 1442 | " \n", 1443 | " \n", 1444 | " \n", 1445 | " \n", 1446 | " \n", 1447 | "
reference_namestartreference_basesalternate_baseschi_squared_score
0121595431AG744.125
1121600977AT828.910
2122129565CT711.515
3122132494TC753.874
4122134197AG822.961
5122138687CA706.309
6122139264AC769.534
7122140624TC704.880
8122141908CT790.150
9126505528TG768.788
\n", 1448 | "
" 1449 | ], 1450 | "text/plain": [ 1451 | " reference_name start reference_bases alternate_bases chi_squared_score\n", 1452 | "0 12 1595431 A G 744.125\n", 1453 | "1 12 1600977 A T 828.910\n", 1454 | "2 12 2129565 C T 711.515\n", 1455 | "3 12 2132494 T C 753.874\n", 1456 | "4 12 2134197 A G 822.961\n", 1457 | "5 12 2138687 C A 706.309\n", 1458 | "6 12 2139264 A C 769.534\n", 1459 | "7 12 2140624 T C 704.880\n", 1460 | "8 12 2141908 C T 790.150\n", 1461 | "9 12 6505528 T G 768.788" 1462 | ] 1463 | }, 1464 | "execution_count": 17, 1465 | "metadata": {}, 1466 | "output_type": "execute_result" 1467 | } 1468 | ], 1469 | "source": [ 1470 | "sig_snps = bq.Query(sig_snps_dataset, \n", 1471 | " results=results,\n", 1472 | " grouped_counts=grouped_counts,\n", 1473 | " snps=snps,\n", 1474 | " exp_groups=exp_groups,\n", 1475 | " allele_counts=allele_counts,\n", 1476 | " sample_info_table=sample_info_table,\n", 1477 | " variants_table=variants_table).to_dataframe()\n", 1478 | "sig_snps[:10]" 1479 | ] 1480 | }, 1481 | { 1482 | "cell_type": "markdown", 1483 | "metadata": {}, 1484 | "source": [ 1485 | "Let's visualize the distribution of significant SNPs along the length of the chromosome. The y-value of the charts indicates the Chi-squared score: larger values are more significant." 1486 | ] 1487 | }, 1488 | { 1489 | "cell_type": "code", 1490 | "execution_count": 18, 1491 | "metadata": { 1492 | "collapsed": false 1493 | }, 1494 | "outputs": [ 1495 | { 1496 | "data": { 1497 | "text/plain": [ 1498 | "" 1499 | ] 1500 | }, 1501 | "execution_count": 18, 1502 | "metadata": {}, 1503 | "output_type": "execute_result" 1504 | }, 1505 | { 1506 | "data": { 1507 | "image/png": "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\n", 1508 | "text/plain": [ 1509 | "" 1510 | ] 1511 | }, 1512 | "metadata": {}, 1513 | "output_type": "display_data" 1514 | } 1515 | ], 1516 | "source": [ 1517 | "import matplotlib.pyplot as plt\n", 1518 | "import seaborn as sns\n", 1519 | "\n", 1520 | "#g = sns.distplot(sig_snps['start'], rug=False, hist=False, kde_kws=dict(bw=0.1))\n", 1521 | "fig, ax = plt.subplots()\n", 1522 | "ax.scatter(sig_snps['start'], sig_snps['chi_squared_score'], alpha=0.3, c='red')\n", 1523 | "ax.set_ylabel('Chi-squared score')\n", 1524 | "ax.set_xlabel('SNP position (bp)')" 1525 | ] 1526 | }, 1527 | { 1528 | "cell_type": "markdown", 1529 | "metadata": {}, 1530 | "source": [ 1531 | "Let's zoom in on one region that contains a large number of very significant SNPs:" 1532 | ] 1533 | }, 1534 | { 1535 | "cell_type": "code", 1536 | "execution_count": 19, 1537 | "metadata": { 1538 | "collapsed": false 1539 | }, 1540 | "outputs": [ 1541 | { 1542 | "data": { 1543 | "text/plain": [ 1544 | "" 1545 | ] 1546 | }, 1547 | "execution_count": 19, 1548 | "metadata": {}, 1549 | "output_type": "execute_result" 1550 | }, 1551 | { 1552 | "data": { 1553 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgQAAAFmCAYAAAAS1oJaAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xl81dWd//HXXbKSANkDCWENmxhiCLIoxCKrEQuVtkzV\n/pCp2NFqGbdK9TfoqOO0M/1pZ6ZVMgxTW52xLRTQBoUSVERZDSEguyBhS25WEpJckrv8/oDchjXb\n3fN+Ph48HuSbe+/33Jzv8vme8znnGJxOpxMRERHp1oy+LoCIiIj4ngICERERUUAgIiIiCghEREQE\nBQQiIiKCAgIRERHBgwHBkiVLmDhxIrNnz3Zt+9nPfsasWbO45557+NGPfkRdXZ3rd8uWLWP69OnM\nnDmTLVu2uLbv27eP2bNnM336dF5++WVPFVdERKRb81hAcO+997J8+fLLtt1+++3k5+fz3nvvMWDA\nAJYtWwbA0aNHWbduHfn5+SxfvpwXX3yRlukRXnjhBV555RU2bNjAiRMn2Lx5s6eKLCIi0m15LCDI\nzs6mZ8+el2277bbbMBov7nL06NGUlpYCUFBQQG5uLiEhIaSmppKWlsaePXuwWCzU19eTkZEBwJw5\nc9i4caOniiwiItJt+SyHYNWqVeTk5ABgsVhITk52/S45OZmysrKrticlJWGxWLxeVhERkWDnk4Dg\njTfeICQk5LL8AhEREfEds7d3+Kc//YlPPvmEt956y7UtKSnJ1X0AUFpaSnJy8jW3JyYmtrkPp9OJ\nwWBwb8FFRESCmFcDgs2bN/Nf//Vf/O53vyMsLMy1fcqUKTz55JMsWLCAsrIyTpw4QUZGBgaDgaio\nKPbs2UNGRgZr167lgQceaHM/BoOB8vK6Nl8n/ichIVp1F8BUf4FN9Re4EhKiu/wZHgsInnjiCXbs\n2EFNTQ05OTk89thj5OXl0dzczMKFCwHIzMzkhRdeYMiQIcyaNYvc3FxMJhNLly51PeEvXbqUJUuW\nYLVaycnJYfLkyZ4qsoiISLdlCNbljxXlBiY9oQQ21V9gU/0FLne0EGimQhEREVFAICIiIgoIRERE\nBAUEIiIiggICERERQQGBiIiIoIBAREREUEAgIiIiKCAQERERFBCIiIgICghEREQEBQQiIiKCAgIR\nERFBAYGIiIiggEBERERQQCAiIiIoIBAREREUEIiIiAgKCERERAQFBCIiIoICAhEREUEBgYiIiKCA\nQERERFBAICIiIiggEBERERQQiIiICAoIREREBAUEIiIiggICERERQQGBiIiIoIBAREREUEAgIiIi\nKCAQERERFBCIiIgICghEREQEBQQiIiKCAgIRERFBAYGIiIiggEBERERQQCAiIiIoIBAREREUEIiI\niAgeDAiWLFnCxIkTmT17tmvbBx98QG5uLiNGjODLL7+87PXLli1j+vTpzJw5ky1btri279u3j9mz\nZzN9+nRefvllTxVXRESkW/NYQHDvvfeyfPnyy7YNHTqU//iP/yA7O/uy7UePHmXdunXk5+ezfPly\nXnzxRZxOJwAvvPACr7zyChs2bODEiRNs3rzZU0UWERHptjwWEGRnZ9OzZ8/Ltg0ePJiBAwde9dqC\nggJyc3MJCQkhNTWVtLQ09uzZg8Viob6+noyMDADmzJnDxo0bPVVkERGRbssvcggsFgvJycmun5OT\nkykrK7tqe1JSEhaLxRdFFBERCWp+ERCIiIiIb5l9XQC4+ORfWlrq+rm0tJTk5ORrbk9MTGzXZyYk\nRLu9nOIdqrvApvoLbKq/7stnAUFL0iDAlClTePLJJ1mwYAFlZWWcOHGCjIwMDAYDUVFR7Nmzh4yM\nDNauXcsDDzzQrs8vL6/zVNHFgxISolV3AUz1F9hUf4HLHYGcxwKCJ554gh07dlBTU0NOTg6PPfYY\nvXv35qWXXqK6upqHH36YESNGsHz5coYMGcKsWbPIzc3FZDKxdOlSDAYDAEuXLmXJkiVYrVZycnKY\nPHmyp4osIiLSbRmcrR/Vg4ii3MCkJ5TApvoLbKq/wOWOFgIlFYqIiIgCAhEREVFAICIiIiggEBER\nERQQiIiICAoIREREBAUEIiIiggICERERQQGBiIiIoIBAREREUEAgIiIiKCAQERERFBCIiIgICghE\nREQEBQQiIiKCAgIRERFBAYGIiIiggEBERERQQCAiIiIoIBAREREUEIiIiAgKCERERAQw+7oA0jab\nzUZJUSEAaZlZmM2qNhERcS/dWfyczWbjyIo8MquqACgq3EX6wkUKCkRExK3UZeDnSooKyayqwmQ0\nYjIayayqcrUWiIiIuIseMwOEzeHgeOlZHA4HNrvd18UREZEgoxYCP5eWmcWuXr34snAXQ786Su/S\nszTv/gKbzebroomISBBRQODnzGYz4VnZpCT3oWrwEBKyssmqqVG3gYiIuJW6DAKAyWQipm8KJuPF\n+M3ucPi4RCIiEmzUQhAA+o7KoOD8eSpOnaTZZqMoNpa0zCxfF0tERIKIAgI/Z7PZOP7bFeRERlIJ\nrG+oZ+D3F2rYoYiIuJUCAj/XMuwwzGxmWGo/ZkVFc2Zfsa+LJSIiQUYBgYiIiCgg8HdpmVkU9u5N\nxamTVJw6SWHv3sofEBERt1NHdABwOJ1Utvp/e2kNBBERaS/dIfxcSVEh2efOYUrtB4D93DkOFBUy\nKPvWG75PayCIiEhHqMsgSGkNBBER6QgFBH6uZeriQ6dOcujUSXb16qUcAhERcTsFBAHAaDAQB8Rd\n+n97pGVmURQbi93hwO5waDIjERG5IXUo+7mSokKyampcOQQxNTXtyiEwm82kL1zEgUvdBOlKKhQR\nkRvQHcKPWK1Wdq58F4Bb5szDcnA/pw/uZ5jD4VrHoCPMZnObgYOIiAgoIPAbVquVbT9cSG5lJTan\nk5X/+SZzps0k3WjkL4cPMm3ocIxGI0WxsaSr6V9ERNxMAYGf2LnyXXIrKzEbjRyrq+V7585x/OB+\n0jIyuXPocDalpZEyfGS7m/41B4GIiHSEx5IKlyxZwsSJE5k9e7ZrW01NDQ8++CAzZsxg4cKF1NbW\nun63bNkypk+fzsyZM9myZYtr+759+5g9ezbTp0/n5Zdf9lRx/ZrZaCRl+EgGZd/a7mDgyIo80jd8\nSMhv/5vNLzyH1Wr1QklFRCRQeSwguPfee1m+fPll2/Ly8pg4cSLr169n/Pjx5OXlAXD06FHWrVtH\nfn4+y5cv58UXX8R5aUa+F154gVdeeYUNGzZw4sQJNm/e7Kki+9Qtc+bxB6ORunPn6BcRyf/06kXS\n8JGdGiFQUlTIqIoKDu/ZzYivjzN7TxG7Xn4Bm83muS8gIiIBzWMBQXZ2Nj179rxs26ZNm5g7dy4A\nc+fOZePGjQAUFBSQm5tLSEgIqamppKWlsWfPHiwWC/X19WRkZAAwZ84c13uCic1m4+T//Ja7xo7j\ns759ebtvXyat/ZAjM+/iwNTpnZph8OvSs4xubMRkMGAyGMiqPaeJiURE5Lq82rFcWVlJfHw8APHx\n8VRWXpyh32KxMHr0aNfrkpOTKSsrw2w2k5yc7NqelJSExWLxZpE9xmq1su3371B1soSYlH5Mr6gg\nJDSUOzOzsDscHDh6uNMjBNIys9i8ZhXDnU6cQGlEBL2S+1Dq3q8gIiJBxGeZZgaDAUM7J9npjISE\naI99dldZrVa2PPQAA4qL+abNxiagdtgwUidMwGg0Ync4iInp0aXv8M1f/j8+WbKEW86do2/fvuxL\nSGDMtJyASC7057qTtqn+Apvqr/vy6t0hLi6O8vJyEhISsFgsxMbGAhef/EtL//r8WlpaSnJy8jW3\nJyYmtmtf5eV17i28G3369m8YfOQrRjQ1YzIYyHE42FRyEmd8EjF9Uy4OLew/rMvfIeOZf+B4USHH\nudhqUF3d6J4v4EEJCdF+XXdyY6q/wKb6C1zuCOTanUNQdWnVvK6YMmUKq1evBmDNmjVMnTrVtT0/\nP5+mpiZOnjzJiRMnyMjIICEhgaioKPbs2YPT6WTt2rWu9wQTs8FASr80vrh1XKdzBq75uZcmJmrv\n6AQREem+2rxL7Nmzh8WLF2O329m8eTPFxcX88Y9/5KWXXrrh+5544gl27NhBTU0NOTk5PP744yxa\ntIjFixezatUqUlJSeP311wEYMmQIs2bNIjc3F5PJxNKlS13dCUuXLmXJkiVYrVZycnKYPHmyG762\nb42dN5/PNnxI3Zd19GqopyQ8nNCJtzNh/v26cYuIiE8YnC3j+65j/vz5vPTSSzz99NOsWbMGgLvu\nuot169Z5pYCd5e/NXufPn+ejxY9w09mzJAwYSMnNGQz7wQ+7fUCgJsvApvoLbKq/wOWOLoM27z5N\nTU2kp6dfti0kJKTLO+7uLAf3M2/IUExDhwMQ385Fi0RERDyhzRyCsLAwzp8/7/r56NGjhIeHe7RQ\nIiIi4l1tBgQ//OEP+cEPfoDFYuEnP/kJ3//+93n88ce9UbaglpaZRVFsLHaHo1OzEYqIiLhTmzkE\ntbW11NTU8OmnnwJw++23079/f68UrisCoR9MCxBdTX2YgU31F9hUf4HLHTkENwwIHA4Hubm5fPDB\nB13ekbfpoA5MuiAFNtVfYFP9BS6Pz0NgNBrp27cvNTU1Xd6RiIiI+K8226h79OjB3LlzycnJISIi\nArg47fAzzzzj8cKJiIiId7QZEKSnp1817NCTaxCIiIiI97UZEDz22GPeKIeIiIj4UJsBQUNDA7/+\n9a/5/PPPgYujDP7u7/7O1X0gIiIiga/NeQheeuklysvLee655/jpT3+KxWLhH//xH71RNhEREfGS\nNlsI9u3bx/vvv+/6ecyYMdxzzz0eLZSIiIh4V7uWP66vr3f9v6GhwWOFEREREd9os4Vg9uzZzJ8/\nn9zcXJxOJ+vWrVMLgYiISJBpMyBYtGgRw4YNY+vWrRgMBp5++mkmT57sjbKJiIiIl7Rr8vycnBxy\ncnI8XRYRERHxkTZzCObPn8+5c+dcP1dXV3Pfffd5tFAiIiLiXW22EDQ2NtKrVy/XzzExMZclGUrb\nrFYrO1e+C8DYefMJDw/3cYlEREQu12ZA4HA4aGhoIDIyErg44sBms3m8YMHCarWy7YcLya2sBCB/\n4wbGv7lCQYGIiPiVNrsM7r77bhYuXMjatWtZs2YNf/u3f8vs2bO9UbagsHPlu+RWVmI2GjEbjeRW\nVrpaC0RERPxFmy0EDz/8MImJiWzatAm4mFMwZ84cjxdMREREvMfgdDqdvi6EJ5SX1/m6CMA1ugzi\n4tRlcAMJCdF+U3fScaq/wKb6C1wJCdFd/ow2uwxeffVV6urqsNlsfO9732P06NGsWbOmyzvuLsLD\nwxn/5go+/O7f8OF3/0bBgIiI+KU2A4LPP/+c6OhotmzZQlJSEhs2bGDFihXeKFvQCA8PZ9L9C5h0\n/wIFAyIi4pfaNTERwI4dO5g2bRpJSUkYje1aAkFERCTg2Ww2SooKAUjLzMJsbvetM6C0+a3i4uL4\nh3/4Bz799FMefvhhmpubsdvt3iibiIiIT9lsNo6syCOzqgqAosJdpC9cFJRBQZuP+r/4xS8YNGgQ\nr732Gr169aKsrIwHH3zQG2UTERHxqZKiQjKrqjAZjZiMRjKrqlytBcGmXS0ECxYscP2cmppKamqq\nJ8skIiIiXqZkAA+wWq18+vZv+PTt32C1Wn1dHBER6aS0zCwKe/em4tRJKk6dpLB3b9Iys3xdLI8I\nvk4QH2lJOrE2NVG27Ffcfam/SVMVi4gENofTSWWr/wcrtRC4QUvSyYiNGzj3H68z5ct9mAwGTVUs\nIhLgSooKyT53jmGp/RiW2o/sc+e6Xw7BO++8c8M3agnkv2pJOnEC5edqMdXXYz1fR0R0T18XTUSk\n2+ouwwXd5bp/nb1792IwGKiurmbHjh1MmDABp9PJtm3bGDdunAKCK9gcDg7v2c23DPCR3c6E8nLM\nkT1YFx/P+HnzfV08EZGg0N6bvLuGC6ZlZlFUuOuvnxMbS3p3yyH453/+ZwAWLVrE2rVr6devHwAn\nT57k5Zdf9k7pAkRaZhZ/WbOK2Q0NmIxGbsrIYKc5lLOjRnHXU0uUPyAi4gYducm3Hi4IkFlVxYGi\nQgZl39qhfZrNZtIXLuLApSAkPYhbGtr8VqdPn3YFAwD9+vXj1KlTHi1UoDGbzfSbPYfy2lpMRiN9\nk/vQBzgwdbqCARERN3HXTb6jzGazx/fhD9pMKoyPj+dXv/oVFouFsrIy3njjDRISErxRtoAycMxY\nToy6mZ7JfXBysVnJ10NTbDYbx3bt4NiuHdhsNp+WRUTEm9IysyiKjcXucGB3OPzimuzv2lz+uKys\njJdffpkdO3YAMG7cOJ577jmSkpK8UsDO8sUSnv6UwHJV01psbEBMt6nlVwOb6i+w+Xv9dfS65k/X\nZE9zx/LHbQYEgcqfD2pvOLZrByM2bnA1rdkdDg5Mne73zV7+fkGSG1P9BbZAqL/udJPvCHcEBG12\nGTQ0NPDaa6/x5JNPAvDVV1+xcePGLu9YRESko1r68wdl36pgwM3aDAheeOEFbDYbBw4cACApKYl/\n//d/93jBgoWv+vHVfyYiIh3RZnh16NAhfv7zn/PZZ58BEBUVRZD2MridL5fN7E5DZUREpOvabCEI\nDQ297OcLFy4oIGgnXy6bqX42ERHpiDYDguzsbN544w0uXLjA9u3b+fGPf8yUKVO6tNO33nqL2bNn\nc/fdd/PWW28BUFNTw4MPPsiMGTNYuHAhtbW1rtcvW7aM6dOnM3PmTLZs2dKlfXcHVquVbS88T/Jv\n/5thGz7kyIo8DTsUEZEbajMgeOKJJ3A6nfTo0YN/+Zd/ISMjg8cee6zTOzx8+DArV65k5cqVrF27\nlo8//piSkhLy8vKYOHEi69evZ/z48eTl5QFw9OhR1q1bR35+PsuXL+fFF1/E4XB0ev/e5It+fJvN\nxucvL2XGnt0kf32cc3t2k1FREbSLcYhI96W5Vtzrhu3IdrudF198kZdffplHHnnELTs8duwYGRkZ\nhIWFATB27FjWr1/Ppk2bePvttwGYO3cuDzzwAE899RQFBQXk5uYSEhJCamoqaWlpFBcXk5mZ6Zby\neJIv+vFLigpJr63FYDBgMBhIbmyktPSsR/cZTFq6Wmx2O3a7nbIjh3DY7ZhMJvoOH8nAMWPV/SLi\nB3yZoxWsbviXM5lMHDp0yK07TE9P57XXXqOmpoawsDA2b97MqFGjqKysJD4+Hrg4O2Jl5cXVpy0W\nC6NHj3a9Pzk5mbKyMreWyZPcOeWl1Wpl2+/foepkCUNzphAWGorJZLoqR2BAch++OHuGnhUVOJ1O\njkRFc5tGGLSp5QIzqqKCfYW7aDh1ij5NTTjO1zKiZy9qBw7i0J3TGPaDH+qiI+JjvprGOJi1eVUb\nP348//iP/8icOXOIjIx0bR8yZEindjh48GAeeughFi5cSGRkJMOHD8dovLznouXp9npu9LsW7pik\nwZ9YrVa2PPQAA4qLyW1u5uP/fZvBo0fTZ9w49h3ex82PPorZbCZmWg67D+wh9EsziWYjVWFhpA0b\nTEJCdMDcxHxVd4e3beO2C/V8VVtFwrlqnOdrsTc3M8Jux3HBSuS5aqKPH6HmxCGGjh/vkzIGgmA7\n97qb1vV3sUl+FwCDsrP96hpSHdODHj3CLpt8LSamh46/LmizdvPz8wH4+OOPL9u+adOmTu903rx5\nzJs3D4DXXnuNpKQk4uLiKC8vJyEhAYvFQmxsLHBx3oPS0lLXe0tLS9s1bbK/z7bVUZ++/RsGH/mK\nEU3NfNXUxNTGRmqOHacssQ+DG5v54i+fuCLj5qGjSNlZiC0hmX7JfXCeLb/s9/7MlzOlVVfXU19/\ngQZrM0abA6PdgcPhxOl04nA4aW6209jYRHV1fdAdX+4SCDPdyfW1rr8rm+Q/L/jEr5rko/sP47Ow\nTy6fxrj/sG57/LkjEGqzZrty47+eyspK4uLiOHPmDBs2bOAPf/gDp06dYvXq1SxatIg1a9YwdepU\nAKZMmcKTTz7JggULKCsr48SJE2RkZLi9TMHEZDIR0zflsshZ2tay7vlwm40tIWacoaEYjUbKGm2M\nCgvjQEgIlugobh+l40+Cn783yWuuFfdr91+vsrKSCxcuuH7u27dvp3f6+OOPU1NTg9lsZunSpURH\nR7No0SIWL17MqlWrSElJ4fXXXwcudk3MmjWL3NxcTCYTS5cubVeXQbAZO28+n234kLov6+hht/MH\no4lbU1JJTEy6GBm3yhFoubFdFjkrh6BNZrOZgd9fyGcvv8BNQ4ay3wHxjfXUjxjJHysrmZ0+lDE9\noin+7Qq/elISCWY3mlOluyxL7C1tLm60detWnn32WSoqKjCZTDQ1NRETE8PWrVu9VcZOCcZmo/Pn\nz/PR4ke46exZYtL680VsDP3v+dY1M98DdWIiXzc5tywKdaz0LMOOfYUR2BHdkzG156gaPISYvikB\ns1CUL/i6/qRrbtRl4IsVU/2hDIHCK10GP//5z/nv//5vnnjiCVavXs3KlSs5depUl3csHWc5uJ95\nQ4ZiGjocgGSHgwMm0zVPDkXOIsHHm4F+Z5vk3VlGf++2CDZtTkwEMGjQIGw2GwaDgW9/+9t8+umn\nni6XiE+0TCaVlpjE7vBwToeHM2LESPLj4ohKTNJCUeIzLU/LIzZuYMTGDV6ZgbSjKwv6ooziPm3W\ncEhICACJiYkUFBSQkpLCuXPnPF6w7qS9EbVyAzyv5anoSFEhzjunUQqUm0yMH/Ush/YVA0peEt8I\nhKdld5dR1zzvavOq9sADD1BTU8PixYt54oknqKur46c//ak3ytYtdGS2LWXVesf1ulv86cIr0h3o\nmuddbSYVBip/TGy6VktASxJb6yGCHUlYC9TkwetRUlpgU/15jjcS7Lpaf4GcBBjo11KvJBW+8847\n19x+3333dXnn3cn1WgI88ZmBdiCLSNsC4Wk5EMp4LbqWXtTmt927d69r3L/VamXHjh2MHj1aAUEH\nXa9vrSt9ZIHQp+ivWq8LMXLKNIbcOr7bnfwSeAJh9FAglLE1m83G1nffZsy+vRj6pmA0GrvttbTN\nK+A///M/X/azxWLhxRdf9FiBAlVnm5sCNaIOZFarlc8WLWDA/v3MtjVzOP99Dty/gBEPP6K/vUg3\n0tIyMGDfXhKOH6O8rJTYW8b4ulg+065hh60lJiby9ddfe6Aogas9Q21ahrPZHY6rhq51dGjPjT6z\n76gMrQ/OjddJ37nyXUaUlJBltxFiNDLCaiXx809dAZ2IdA8trayD+6ZQHBlJQkMDVWdOd9uhxR3K\nIXA4HOzdu5e4uDiPFirQtKfp3hMtAVd+5sBRGRz/7Ypu3w/Wlf7AQE8sEmlNx3P7mI1GRtwyhoNn\nTvP1reOYMP/+bvm36lAOgclkYsiQIRp22Eme6Ftr/ZnHdu1QTgFtB2gt60I07j9Ppq2ZwxERVEyc\nRPqoDCUWScBo62avRLnLtfy9bHY7Bi7ez/qOynDlcBmA86NuZsL8+4GL11PoXoFUh3MI5Gr+OHmG\nzeHgqzOnOX1w/1UHdHd/aggPD+e2vN+w7ffvsOdSUuGIW8crSVMCRntu9u48ngP9mtHy9xpVUcHB\nokKSgdjMLIoLdzHw+ws50GrSMaDbBlJtfsOf/exnV60u2DJ1gcFg4JlnnvFMyQKIvyQGtgQmrQ/6\nKSUlFK/Icx3Q3eGpoT0BWnh4OHf8n7/1RfFEusybwas3rxmeCjxa/l7HLGXcYrViBMotZWQajRzY\nV+z6u3X3EQdtJhVWVFTwwQcfYLPZaG5u5sMPP6SyspIePXoQGRnpjTIGhM4mBrq7DOkLF/FxWhop\nyX1IyMomxGwms6rKdZK1vpCYLh3swZZM5wrQpk7nwNTp7b543SjxUyTQdPV4bknM3fru22RUVHj8\nmuHrdRBcIw52bCfh+DGqdn+Bw+Hw2v79QZtXydLSUv70pz8RExMDwCOPPMLjjz/Oz3/+c48XTjrO\nbDaTMnwkMadOYTR2eBBJ0OhMvoa/tPSItKU9rWBdOZ5btwqEnDlNVelZErKyPXpN8WSrh6v11OFg\n95nTF7sMEpMu+7u17N/ZN4XislIyGhooP3OaE6Nu9nkXsLe0eXRUVFS4ggGAmJgYKioqPFoo6bjW\nTW2tE2WsNhvvfHUEa8lxTuwt5pa58yhY8yeyas/RK7kPxfHx3eZgl+AX6H3d7dXem31nE5lb35wH\n903hy9KzmM6cJqZvil/kSHXU9RYtu9bfrTuPOGjzW6anp/Pcc88xb948nE4nf/rTn0hPT/dG2aQd\nbDYbx77Yyck//ZEBe4sxGAwcnJnL8Id+yO7CXRx69SX6HzpAbrONsr9sYMOK/+SeaTM4BWxrqGfi\n95/pNgd7W7pDfkUw6271560ZAc1GI8Mzsy52RQ4f6bGWM08nZ7f192q9/9YjDoL1+LmWNhc3qqur\n41e/+hU7dlwcgjFu3DgeffRRoqKivFLAzuoOC6y0XABNRYWE/fk9bnY4MIaGsicsjLplv6G65Dih\n//Y60yssmA1G9tuaMQOfJiaTnJ7OuJGjOD7zLr9KlvHl4jhdXWhKVH+BrqX+fLVIka9beHy9/67w\nyuJG0dHRPPvss13ekbhfS7Ne3r4vecxmI9RoxO5wcLP1Aq///m3SJ9zmeq3N6eRAUxMmh4P7zp7G\nXl3JhuPHiJ8y1YffQET8ka/yaXy9DoKv9+9rbWaIrFixgrq6ixH/008/zcyZM/n00089XjBpv55R\nUewxGLE7ndidTvaYjEQnJTN23nzODR3Kn80h7Gtq4pzdznink9DQUCKdTiaeP0/5kUPAjaf6DTbX\n+64aZRDYVH/u5Q8jp8S72qzl1atXs3DhQrZt20ZVVRWvvPIKr7zyCpMmTfJG+eQGWvq8Zt46jvcP\nHcDYdIHQiEj2JCYy64mfEB4ezuTlv+Wj3yxnzS//H9nnDcTZbZxraiKkZy9C4uIwmkzdqu/1Rt9V\nowwCm+pPpGvabCFoGWayfft27r77bsaMGUMbaQfiJWazmYHfX8gXNht3TJtB0agM3r/pJu54b70r\nxyM8PJzHtkHAAAAgAElEQVSoqCieGjyE3klJfGAyc76piaUV5fzk5En63X4HJUWFjLJYOL2vmNP7\nihllsQTd3AQt2pqHQU9FgU31J9J5bZ4x4eHh5OXl8ec//5n/+Z//weFw0Nzc7I2ySTuc2VfMnVFR\nmHr2ZMCgwRcTqY4epvcV/WBmg4Hsvil8EhrKyqNHeBUw1NXyxu3ZDHjjvwj/83sMrD0HwPGjR2lS\nboGISLfSZgvBq6++isVi4emnnyYhIYFTp04xe/Zsb5RN3GTsvPnkx8WB00nB6dM8CoQZjYQajfxd\nUxNr/uFZyqsqCLc2Em5tpLyqgtMH9/u62B6hfmbxtu6UnyOBrc0WgkGDBvH8888D8PXXXzNgwAAe\nfvhhjxdM2qe98/aPf3MFH658l5ozpzCcbMDmdHLM6aQZcDQ1MT4ikq8uXazGm828c+a0t79Kl7R3\nuJD6mcWbulN+jgS+NuchaG3OnDmsWbPGk+Vxm+4wD0GLjoydPXXqFAVjb+Y2u51MoNBgYN9372Pg\nzm3kNDYCsDkikrBf/JIRE2/3RvEv05lx7L4aMy1X8+U8BP4o0OZGUP0FLq/MQyD+r71jZ202G9Xv\nryZ2+Eis+79ku9FI0q3juDcxkU05U9hW8jUAxtsmkX7reA+X2n26y7LFLbNSlh05RHL6MAaOGaug\nR0TcpkNXk1tuucVT5RAvKCkqJPrLLxlcUc6EHpGYDAYqjx/jfFp/Uu7/P5hNJiDwZujqDmw2Gwf+\n8w3CPypgZmMjpRERHJoylWE/+KHqyo95ejpeEXfq0JVk6dKlniqHeMnZqgqmGI0Um8yMttuIaG5m\nndXKjAB+2uwOF92SokJ6H9jPCKsVk9FIitWKaf+XlARhS0gwUc6KBJLrHpk///nPeeaZZ3j88cev\n+p3BYOCXv/ylRwsm7peWmcVXAway7/Bhbo6E3Q4HJ/r0ZeCDPwjoi5QuuuLPuvt0uBI4rnvVzM7O\nBuCOO+646ncGg8FjBRLPMZvNTPqHl9iOgQtfHyMqNp64m25iaADlC1yP2WwmLTOLkqJCSooK6Tsq\ngzP7ioHg6AJJy8ziwM7t7C49S+alLoOSkTcxrB0tIYG8YIuIeE+HRhkEEmXKXl/rG4S/3Tg7m+Xc\neqSBzeGg4PBBpg0djtFoDJpRB51JKvT2CAxlqQc21V/g8soog4qKCn73u99x8uRJ16Qa6jIIbC1N\nmME0Rrr1SINjpWfJraykylJGTN+UoBl1YDabGTpuAkPHTXBtO3/+PH/+11cpO7ifkXfOZNID/4fw\n8HDX77vLCAwR6bo2r/yPPfYYQ4YMYeLEia51DdRlEBx0swhs58+fZ/2sKfT7+jiL7HYsn3/Glk82\ncfvyty4LCqR91LUi3V2bR3xdXR0vvfSSN8oScHQB8R+tRxqkJSaRX1PNtMQk1/TEwTbqAGDD6/9C\n2tmzTLU7CDEaSbE7mLh3DztXvsuk+xcA3WMEhjsEU2uZSGe1ebSnp6dTVlZGUlKSN8oTMILhAhJM\nN4srRxqMf+IZDl3KjejOow40AqN91FomcoOAoGW4YX19PbNnzyYrK4vQ0FBAOQQQHBeQYLtZXDm8\nK5DqojOmL36a9es/4P2vj3NnczNVJhPbRt3MpHnzL3udhr2JSHtc9+rfMtzQYDCQm5t72e+UQxA8\ndLPwD53pfoqKiuLO9zfw/sL7+H3JSRIGDyJhwm0BHdT5SjC1lol01nWHHdpsNpqamoiMjLxse0ND\nA6GhoX5/0fH00BktqOMZ3XHYU1eOJX9bPCeQ6085QYFdf92dR4cd/uIXv2DgwIF85zvfuWx7fn4+\nx48f55lnnunyzgNZsDW3B4NAu6C3lPf0wf1Mtlg4VlEOwCiHgyMB1v0UDNRaJt2d8Xq/2LZtG/fe\ne+9V27/1rW/xySefeLRQgaLlAjIo+1a/v/kEu5an7BEbNzBi4waOrMhzzZvhj1qXN3XbVnbnv8/Q\nr44y7NhXHCwqxGa3t+tz0jKzKIqNxe5wuEZUpKmpW0Q64bp3MbvdjunS6netmUwm13wEIv7CX5M8\nr9dq0bq8TQ47PcrOst9SysHwCA477DT+7BV6xicQ1zeFm6fPZMit413vvfIz1VIlIu5w3SvHhQsX\naGhouCqHoL6+nqampi7tdNmyZbz33nsYjUaGDh3Kq6++SkNDA3//93/PmTNnSElJ4fXXX6dnz56u\n169atQqj0cjzzz/P7bff3qX9i3hDe4amnm9qYtuGD5l9/jyFgKmujlEAWzbTDxgeGkrJh/kceOBB\nRjz8CMA1P9PXgY8nBFoXkEigu+6j/l133cWzzz5LXd1fE0xqa2t57rnnmDlzZqd3eOrUKf7whz+w\nevVq3n//fex2O/n5+eTl5TFx4kTWr1/P+PHjycvLA+Do0aOsW7eO/Px8li9fzosvvojD4ej0/iU4\n+WPTeetWAJPRSGZVFSVFhdhsNmx2Oxtqa/nNh+uYfL6eAiCUixF6ODASuAU429yMo6yU2C2fUFJU\nyPEvdtJ/315qS89iANdnBptA6wISCQbXDQgeeeQRQkNDmTx5MnPmzGHOnDnk5ORgMpn40Y9+1Okd\nRkVFYTabaWxsxGazYbVaSUxMZNOmTcydOxeAuXPnsnHjRgAKCgrIzc0lJCSE1NRU0tLSKC4u7vT+\nPc1ms3Fs1w6O7dqhC5gXuZI8p07nwNTpfjviw2a3X7zRFfyF+MMHqD99EoPDTgVwEHAAIYAN2Auk\nO50Ma27m9MkSrE1NnHx/DQnHj5Fw7Cuqdn/hd8HxjY5/m83G4e1b+fTt33Bk+9aLgdF1Xn+9YEpE\nPOe6V8yQkBD+9V//la+//pr9+/cDMHLkSAYMGNClHfbu3ZuFCxdyxx13EB4ezu23385tt91GZWUl\n8fHxAMTHx1NZWQmAxWJh9OjRrvcnJydTVlbWpTJ4irdnL1ST6uX8LUs8LTOLwl076LdvL19Zythh\nsxFrtTLfbKakopzYyip+HBXNLxsaudnpIAY4D9QAx4G7ACuwNySU8IhISg8dZFpkD4ojIxnd2EhC\nQwPrGxoY7ydJhDabjb2/+hUjSs4Alx//NpuNA//5BuEfFTC1oYFdzc0UZGXRN7U/2XW1V71eRLyv\nzTNvwIABXQ4CWispKeGtt95i06ZNREdH8+Mf/5i1a9de9hqDwXDDyY/8dWKkriS2dfTmHgxTJ3cH\nzTYbhYcO4PjqKI8bjBw4fIhT0dE4xtyKEYgymbg5MQlr2VnKuNhNsAdoBA4DVT2imJrWn4iwMN75\nfAvGgYMYccsYDpWexeFwkDj7m35T5yVFhWRXVmK9xvFfUlRI7wP7SW9s5ICljNuamthTUEBkTAyG\nb9yJ8VIrQMvrNVGQiPd5/Uqyb98+brnlFmJiYgCYNm0aRUVFxMfHU15eTkJCAhaLhdjYWACSkpIo\nLS11vb+0tLRd6yq4Y5KGjqqO6UGPHmGXTRITE9OjzbK0PFllX2oVKT68j5sfffSGF/rD27Zx24V6\nTNERANx2oZ6vThxi6Pjxbvo2vuOLuvOEw9u2kXryOI7680wxGDAb4GacFDU2EFNXzbk+SXxma2JG\nXBy/qK0hq7GRQ8C9QDOwKiyMeyMjICyE2phePDByGJsbG5naI5qbBw+gOC6OcTOn+E1AUB3TA4Ae\nPcKAy4//6pge2CNCOWVtYIzDjtFsIjTERJrDRkN1OecMBuxOJ9HRYa76T/jJkxzbtQuAidnZfvM9\ng12wnH/ScV4/wwYNGsSvf/1rrFYrYWFhbN26lYyMDCIiIli9ejWLFi1izZo1TJ06FYApU6bw5JNP\nsmDBAsrKyjhx4gQZGRlt7scXs21F9x/GZ2GfXP5U039Ym2U5tmsHI0rOcB44cuY0Jz/bytajxxk1\ndQZmkwmTyXRVq0F1dT319RcuCz6qq+sDfpaxYJoprbq6npDGJmx2B06nEydgdMLgXjGsSR/OqGkz\nMdvtrD9yiFCngeSi3TQ1NnDGYCAiLJyBvXtTGh5OU2IyqTdl0HzBTtSds9h1aThwWmYW1dWNvv2S\nrUT3H0Zx3HYGt3QZtDr+o/sP48CAIVQVFTPQZqcxJISoPinsxomtaA8TQsMojYig5KNPiRl8k+tY\njxl8E4Bffc9gFkznX3fj0ZkKPWX48OF885vf5N5778VoNDJy5Ei+853vUF9fz+LFi1m1apVr2CHA\nkCFDmDVrFrm5uZhMJpYuXerzLoPrNe93ZfZCm8PB/t1fYDh+jJSaajL3FrP9T6sYnpRI2qQ72HdF\nl4CaVP1fWmYWB3ZuJ+L0Sf5cXc00ux1rRASfDBjAXU8tITw8HICw0FByTp7kE0sZSWWlfGm1MhCI\nG5LOF9HRTB82AieX6njMWL99Ujabzdz86KN88ZeLE5elX3FujHjo7zg8+hbe/e/l3BEeTnyfvuw4\nX8fEujqqTCYSkvsQX1PjF/NHiHRH113LINB5Ksr1xBoGNpuNzS88x/Atn2IqK6VfUxMf2+1Mdzhw\nRkVxIq0/fSbfwaHpMy+7UAZjUmGwPaHYbDaOfbGTk1/upfrUSRL6D2Dcd+9zBQPw1/UIGm02Pvgg\nn2G156hM7UddVhbjlyzFcvBiUm8g1HF76q/1cWu32xn1UYHfrMXQ3QXb+dedBGQLQaDzxIx4ZrOZ\nfrPnUHPsK3o0NnCytpYhDfUYDeA0GOhz4QLnSs9e8326cPo3s9nM0HETGDpuwnVf09LaE7VvL9+J\njaU8NZVRt4zBCRw4uD/o6rj1cWuz2Sjas1stXSJ+QAGBnxg4ZiwHJuXQ0NTEiYMHmWIys9NsZkRE\nBOE9elDYs5ffDC+TzrtWq05LV9PWd98mDojtm4LRaMTuZ3MMeIIWCRPxHzrzOshTffctfazHsrJp\n/nIvaz7fwqSwcL42GDnauxcTn39BF8oAd6OhomazmQnz7+dIQwMxVVWu2Ra7w9OyWrpE/INyCDrB\nG333wZgf0B7B3IfZkivQ0t10wWbj47Q0UoaPdNXxlfUOBNRxEMz11x2o/gKXcgh8xBtPNHpqCm42\nh4ODRYWMKT1LzKlTl7UWtO5f1+RT3tVdA3ERuMFaBuIZ3lzrQOsq+JfWCzB9deY0yVzMF7jeXP2a\nz9+7tKCSdHcKf73Im098err0P60T6E4f3M+UkhKMRsXk/sITI4hEAomuRl5UUlRIRkUFtaVnqS09\nS0ZFhcee+PR06b9sdjt2u52C8+dpttmuu1yzPy7pLCLBS4+LXmS326kqKiTFagXg9JnT2O+c5uNS\nibe0XvEvt7GRU2FhfDBsGP3v+dY1ZyDUkDzv0uyf0t3p6uJmN0pKcgKlQJ9LP5de2uYJurh5R3uS\n0Fpec/rgfvp/+SUjrVZMRiP9m5oIqzvPKa4/kkDJpd6jAEy6Ox3tXXCtIWI36rc3m0ykZ2ZxyFIG\nwPDEJI5cWqjG3TpzcVOGdce0J0+j9WtCzpym5sghnKGhcGk9DpvDgeX9tdwZFXXdzxDvUQAm3Zmu\nOp10rZuBefQtjLJYOLF/H2dqa4ntP4BjX+x0TVublpnFvsJdZF5KWurMU/uNbtrX+l17L25KQuy4\n9iShtX7N4L4p7Dlzmi2150hqaqYyLIyzUdHkRkYqkU1EfE5X+0661s1g3f4vCf/zWuwVFXzDYafi\n8EE+79mTQWPGut5jGn0L+wDTpdaCjtxwb3TT7ugN/crgwZXweKn1IsPh4JBuTG5lNhoZnpnFn78+\nRt/GRgbFxlFm8u3KnR2lViSR4KWzuYtsDgfHS8/icDgotzYScr6e2Q47JoMBh8PJ0BNfc+yLndiv\nWMBlYCeevm/0RHqt3+39YifmS10SrS/e1woeDKMylPDYQe3J07jyNR9ZG/nWoCGEXKqLGTYbHzU0\n/LXLwI9zPdzRiqSAQsR/6WzspLTMLHbt3E74RwVkNjZSGhGBoaGegbGxVF4KCBJCQqgxGCg7coip\nXh7ffKO+6Wu2bhzcT2N1Nc2WMkLCwjmVloZnshuCx/XyNK686bV+TT+7HeNHBX/9DKORxNnf5MCl\nwM2fE9m6Ok5f3VIi/k1nYieZzWbCs7JJObCfKqORmMQksk6dZKvJxJiISDLtNg5FRFAxcRLJ6cPg\n1Kku7/NGT6RX/u4vDfXMiOzRrou31WbjxHtr6XX0MM12Bw1GA/VGAz3s9i6XOdhdmadxvZveDZf7\nvcaQQ0+z2Wwc+2InZUcOkZw+jIGtytDyuzMH92MAEtOHYTaZKD1yiHSbjdqKcmwOB2U2O0Uf5mO3\n2y97//Vo4h8R/6aAoAtMJhMxfVMurlu/+wsyGxqIGzGS9Res7O4/gFFTZzDi1vEAblnz/UYjB678\n3ZVPoq21Dh5sDgcrd25j+Okz3NTURLLBiNEcSlT9eYqOHGLExNs7XM7urK2bnj8MbWs9H8LMS61b\nh6ZMZdgPfgjAgf98A3PBX+j39dcMcDooDg1lcGo/Bt08mjUFG7g3Kpq9paXUNNRz36DBWIr3XPZ+\nEQlMCgi6oOXGGrVvLxkNDZRHRtI3rT8LgANTp1/25OOum8CNRg5cuTDO9YKQK6fQHXfmDKWlpSSG\nhnHO4aDZbKJ3bDwmDw2J7O7MZjN9R2Ww7ffvUPRhPkNzphAWGorJZPJKv3pJUSG9D+xnxKX5EFKs\nVkz7v3S1GMR9+gm9KioYYbdx9MIFbmtspDk8gr2HDjInKpp36s4zyNbMnaGhNDc2kmIyYdr/JSVF\nhfTpc+d196u5MUT8mwKCLmi5sW59923iuLhQjdFoxO5wXPO13mwabetJtHV5BpaUUNevHx9UV3NX\nczNVYeF8NGAAE+bN91p5g0VLbknvA/sBqBkxkhFX3PSsViufLVrAgP37mdXcxMfv/I5+N40iPiub\nYh/1q7fknAyoPYfpzBkuVFbgvCIgtDkcHC4r41aTkbCmJhqbmzDFxbV7H/7QOiIi16ezsYvMZjMT\n5t/PkYYGYqqqXHPO+8OTT3uCkJa5ETKyxnIwMZl/LTtL+t1zmPA39xMeHu6lkgYXo8FAy22y1nD1\nsMKdK99lREkJ6bZmPm5oYEhjA/Yjh6lNSSXTaLysi8ETWflpmVkc2Lmd3aVnXQmxO3r1ZFZkJIao\nKPaePQN1dexoukB6RAQfmc2ca7pAfVUlt5pNDIlPoNhuZ1+tjZscDk6Hh1My8iaGteOY18Q/Iv5L\nAYEbBPKTT0vZjxQVYgIWBlDZ/VFJUSFZNTWYUvsBEFNTc83EOZvTSVFdHU2NjQyyNXOuuorygwfo\nmZT819d4KCvfbDYz4qG/41hWNh9eSirsDxg/KsBkNHLzmLEcSkpmV2IiJ/v0xfreGr5ZV8tX1dVg\nNFA5cBB9Bw2mzGZnZd8+3DxtJsN8kBgpIu6l1Q7dpOXJZ1D2rQF3YQzksgeisfPms61XT5ptNnLs\ndt41GLA4ncQ1NvBRQ4NrGmxPrlhpNpsZOm4Ck+5fQPq4CfQbfQsF589TceokTocDa8Zo5v50KeER\nEcwHonv1ZlRyMlabnbqqSmL7pnAhM5N7nv2/pI+boONGJAgoIBBxo/YsWRweHk7Gs/+XqhEj2RAa\nwtzQUJwGIysrKug5Y5ZPRh0c/+0KciIjqQTWN9Qz8PsLr1590WBgZHIyn40YyYGp0zWHgEiQUUAg\n4kau7qOp02940xxy63hO9OnLZJOJUKOJwWGhfCcykupjR12vaU9w4Q4tLRFhZjPDUvsxKyqaM/uK\ngYutGflxcdgcDmwOB+vj47nrqSVqTRIJQjqjA0h7E8w0PaxvtTdxzmwy0iMikka7jQvhEfRISsbY\nKrPfH3JTwsPDGf/mCj5c+S4A4+fNV7KpSJDSnSJAtDfBTNPDBoaSokK+M2AQG/d/yV0NDYQD75rN\n3HnFUE9vZOW3NT9AeHg4k+5f4NEyiIjv6S4RINo77aumhw0c4WYzOXd/k798uQ+n08HAHy2+7Onb\nWy09/tASISK+p7NexAdaP5Xn3Jxx8an80jTX4P2WHs0PICJKKgwQ7U0w81YimnRNW8mHnhxyKCJy\nLWohCBDtbdZV82/g0FO5iPgT3SkCSMsNpK2+Zd1oAl+gLAR05bEoIoFLAUGA0SiC7iEQWnqudSwm\n/ORJH5dKRDpLOQQBRn3L3Ye/Tyl9rWPx2K5dvi6WiHSSAgIRERFRQBBoNIpA/MW1jsVB2dm+LpaI\ndJLB6XQ6fV0ITygvr/N1Ea7JHZPNBPPUxAkJ0X5bd3K1K4/FPn1iVH8BTOdf4EpIiO7yZwTPnSQA\ndCQh8EY3fY0iCA7BENjpWBQJHoF3BQpg7Z1W+FqBw8DvL3StQBeoNw/5K40WERF/oxwCP3Rl9vao\nigp2vfwCIzZuYMTGDRxZkYfNZvN1MaULNFpERPyNAoJOsNlsHNu1g2O7dtzwxnzl6zqbEPh16Vmy\nas/p5iEiIh6j9skO6uoyxO2ZbObKWeqO9OzJoMgenvxa4mWBMhOhiHQfCgg6qCPLEI+qqOCYpQyA\nUQ4HRy69rq0krCtnqZs4KoPi367QzSOIBMJMhCLSvXj9CnTs2DGeeOIJ188nT57kxz/+Mffccw9/\n//d/z5kzZ0hJSeH111+nZ8+eACxbtoxVq1ZhNBp5/vnnuf32271d7A6z2e0cLCrkFqsVgN1nTuO8\nc1q7339l9rZuHsHHHRn6wTBSQUT8g9evHoMGDWLNmjUAOBwOJk+ezLRp08jLy2PixIk89NBD5OXl\nkZeXx1NPPcXRo0dZt24d+fn5lJWV8eCDD7J+/XqMRt+kP7S3qdcAxDQ3U3jkMACxw0dQ3YX9aniX\nXEkjFUTEnXyaVPj555+TlpZGnz592LRpE3PnzgVg7ty5bNy4EYCCggJyc3MJCQkhNTWVtLQ0iouL\nfVbmttaxb9HY2Mi5wi+4taaaW2uqOVf4BY2NjT4osXhLe5NN3UUjFUTEnXwaEOTn55ObmwtAZWUl\n8fHxAMTHx1NZWQmAxWIhOTnZ9Z7k5GTKysq8X9hW2rPozPbfv4PRZsNgNGIwGjHabGz//TteLql4\nS8vTuoaGikig8llA0NTUxEcffcSsWbOu+p3BYMBgMFz3vTf6nb8wGY3cFBLCUfPFfzeFhLgSESX4\n+OJpXetaiIg7+ayzcfPmzdx0003ExsYCEBcXR3l5OQkJCVgsFtf2pKQkSktLXe8rLS0lKSmpzc93\nx7zOXfG3v/4PfjN8I3/b0IDRZGJFdDQP571J796+LVcg8HXddUZ1TA969AhzBX12h4OYmB4e/y4J\nP3nSteTwxOxsv8gfCMT6k79S/XVfPrt65Ofnc/fdd7t+njJlCqtXr2bRokWsWbOGqVOnurY/+eST\nLFiwgLKyMk6cOEFGRkabn+/LBTouNh//F7O/ex//vukvVIWG8v13V9PcbNLCIW0I1MVVovsP47Ow\nTy5PNu0/zCvfJWbwTQBUV/s+RyVQ608u8nT9aVSM57gjkPPJaocNDQ184xvfoKCggKioKABqampY\nvHgxZ8+evWrY4ZtvvsmqVaswmUw899xzTJo0qc19+PKidGzXDkZs3HDZ0+KBqdO9NkogkE+6QL6h\nBPLf3V0Cuf7Es/V31aiY2FiNinGjgA0IvKG7BARX3oSAgD7pdEMJbO6oPwVWvuPJ88/XD0rBTssf\n+ylvTUt7rXHo5tG3tGsmRRF/pLkVRHxHae8e0Hqugt2T78ASFsbWd9/GemnWQne5VmZ76ZFDbt2H\n+Bdvz3XgbZpbIXhpVIz/U9jtIWazmb6jMtj2w4XkXppTIX/jBsa/uYLw8HCP7TcpfRhFDQ1a9yAI\n6elZApnW7/B/aiHwoJ0r3yW3shKz0YjZaCS3spKdK9912+dfK+IeNGZsu2ZSFM/w5BN8d3h61lNk\ncGvPpG7iO6qRAHajiFs5A9535RP8rp3bCc/KxmQyKTmunfQUKeI7OtM8aOy8+eRv3PDXLoO4OMbP\nm+/WfWjRI//R+gne5nAQ/lEBKQf2E9M3xS3N+95KVvU1HdMivqGAwIPCw8MZ/+YKPrzUTTB+3nyP\n5g+I/zheepbMxkaqWjXv796xjcpjR4GLwWJHjwU9PYuIJ2keAvErgTwPQesug6NnTtO79CwJWdkY\njUbqm5pYt3M733E4gEutRR5OMPWFQK4/Uf0FMnfMQ6CkQhE3aT3ctPG+71MyZSpOLk7A8scTx/m2\n3e6xBFMRka5Se6OIG7Xu/7aNGetq3k9ISqbxrf+iwWolNDISc2QPXxZTROQqCghEPKQlOLDZbFR/\n/invl5XxPauVJqORd1NTmTJnnq+LKEFC0z2LO+ioCQK6GPi3kqJCEo8eZdzgIWyqsIATbr/pZiwH\n9xOlbHrpIk1YJe6iIybA6WLgv6xWKztXvkv518fJstsJNxq5M6kPTqeTUtWPuEnr4a6g9Uuk83RV\nCnC6GPgnq9Xqmrba5nTy+9pzXEhMIuvCBUojIigZeRPDgnAOAREJXAoIgojN4eCrM6c5fXC/ug58\n7LJpq4Hv9uzF2xmjsQwaTHL6MIaNGav6EbfoLhNWiefpihTgWi4GoyoqOFhUSDIwpaSE4hV56jrw\nI2aDgeRBg5l0/wJfF0WCjCasEnfRPAQBruVi8HFaGinJfUjIyibEbA7KhW8Cydh588mPi8PmcGBz\nOMiPi2Osm6etFmmhRYPEHXTkBAGz2UzK8JHEnDqF0agYzx9o2moRCTQKCIKE+hH9T3h4uLoIRCRg\nKCAIEupHFBGRrtAdI4ho2VgREeksdTiLiIiIAgIRERFRQCAiIiIoIBAREREUEIiIiAgKCERERAQF\nBCIiIoICAhEREUEBgYiIiKCAQERERFBAICIiIiggEBERERQQiIiICAoIREREBAUEIiIiggICERER\nQQGBiIiIoIBAREREUEAgIiIiKCAQERERFBCIiIgIPgoIamtrefzxx5k1axZ33XUXe/bsoaamhgcf\nfJAZM2awcOFCamtrXa9ftmwZ06dPZ+bMmWzZssUXRRYREQlqPgkIXnnlFSZPnswHH3zAe++9x6BB\ng7WKE94AAA1ESURBVMjLy2PixImsX7+e8ePHk5eXB8DRo0dZt24d+fn5LF++nBdffBGHw+GLYouI\niAQtrwcEdXV17Nq1i3nz5gFgNpuJjo5m06ZNzJ07F4C5c+eyceNGAAoKCsjNzSUkJITU1FTS0tIo\nLi72drFFRESCmtcDglOnThEbG8uSJUuYO3cuzz//PA0NDVRWVhIfHw9AfHw8lZWVAFgsFpKTk13v\nT05OpqyszNvFFhERCWpeDwhsNhv79+/nb/7mb1i9ejURERGu7oEWBoMBg8Fw3c+40e9ERESk48ze\n3mFycjJJSUlkZGQAMGPGDPLy8oiPj6e8vJyEhAQsFguxsbEAJCUlUVpa6np/aWkpSUlJbe4nISHa\nM19APE51F9hUf4FN9dd9eb2FICEhgT59+nD8+HEAtm7dypAhQ/jGN77B6tWrAVizZg1Tp04FYMqU\nKeTn59PU1MTJkyc5ceKEK5gQERER9zA4nU6nt3d68OBBnnvuOZqbm0lLS+PVV1/FbrezePFizp49\nS0pKCq+//jo9e/YE4M0332TVqlWYTCaee+45Jk2a5O0ii4iIBDWfBAQiIiLiXzRToYiIiCggEBER\nEQUEIiIigg+GHXbWhQsXuP/++2lqaqK5uZk777yTJ5988rLXbNy4kX/7t3/DaDRiNBp5+umnmTBh\nAgCbN2/mn/7pn3A4HMybN49Fixb54mt0W12tvylTptCjRw9MJhNms5mVK1f64mt0W+2pvxbFxcXM\nnz+f1157jRkzZgA6/3ypq3Wnc8+32lN/27dv55FHHqFfv34ATJ8+nUceeQTo4LnnDCANDQ1Op9Pp\nbG5udn7729927ty587Lf19fXu/5/8OBB59SpU51Op9Nps9mcU6dOdZ48edLZ1NTkvOeee5xHjx71\nXsHF6XR2vv6cTqfzG9/4hrO6uto7BZVraqv+nM6L59oDDzzgXLRokfPDDz90bdP551udrTunU+ee\nP2ir/rZt2+Z8+OGHr3pfR8+9gOoyiIiIAKC5uRm73U7v3r0v+31kZKTr/w0NDcTExAAXo960tDRS\nU1MJCQkhNzeXgoIC7xVcgM7XXwunBsT4VFv1B/C73/2OGTNmuCYWA51//qCzdddC555vtaf+rqWj\n515ABQQOh4NvfvObTJw4kXHjxjFkyJCrXrNx40ZmzZrFQw89xPPPPw9AWVkZffr0cb0mKSlJ6yH4\nQGfrDy5OV/3ggw/yrW99iz/84Q/eLLZc0lb9lZWVUVBQwPe+9z3gr1OM6/zzvc7WXcv/de75Vlv1\nZzAY2L17N/fccw8PPfQQR48eBTp+7gVUQGA0Glm7di2bN29m165dbN++/arXTJ06lQ8++IA333yT\np59+WpGtH+lM/bX43//9X9asWcPy5ct555132LVrlzeLLrRdf6+88gpPPfUUBoMBp9PpOve09ojv\ndbbuQOeeP2ir/kaOHMnHH3/Me++9x/3338+jjz7auf24o7DeFh0dTU5ODvv27bvua7Kzs7Hb7dTU\n1JCcnMzZs2f/f3v3GhTjFwdw/Ju2KPm7hMy4jQm5lGsuGWPNYiYqu5oamR0aIsO4jxk1Likab/AC\nGYNpkktKUUqbFxoMymWMyxAzbmkZXazBErLt/0XTM63kXyzV3+/zqp7f2T3n2TNnn7PnOc85Sqyx\n+yGI36Mp9ffmzRsAunfvDkCXLl2YNm2abIHdjBqqv3v37rF69Wo0Gg1nz54lNjaWc+fO4eHhIe2v\nhWhq3YG0vZakofpzc3NTbiuo1Wqqqqp+6trXajoEJpOJd+/eAfDp0yeuXLnCkCFDbNI8f/5c6dne\nu3cPgM6dO+Pt7U1xcTFGo5EvX76Qm5vLlClT/uwJ/OV+pf4qKysxm81AzdyCS5cuMXDgwD9YetGY\n+jt37hz5+fnk5+fj7+/P5s2bmTJlirS/ZvYrdSdtr/k1pv4qKiqU787aDlunTp2a3PZazWOH5eXl\nREVFUV1drdxP8fPz4/jx4wCEhYVx9uxZsrKyUKlUuLq6snPnTgBUKhUbN24kIiJCefTC09OzOU/n\nr/Mr9VdRUcGyZcsAsFgsBAUFMXHixGY7l79RY+qvIdL+mtev1J20vebX2O/OlJQUHB0dcXFx+elr\nn+xlIIQQQojWc8tACCGEEL+PdAiEEEIIIR0CIYQQQkiHQAghhBC0oqcMhBBCiP+j6OhoLly4gLu7\nO9nZ2T9Mu23bNmVhosrKSkwmE9evX7dLOeQpAyGEEKIZ3bhxA1dXV9atW/efHYK6jhw5QlFREfHx\n8XYph9wyEKIFMhgMzJo1C51Ox/Tp0222O9VoNAQFBdksL6vRaJT1y6OiolCr1eh0Ovz9/dmxY8dv\nL29paSnz5s1T/t+9ezdVVVXK/7t27SI3N9eueX7+/Jng4GAqKysB28+gKfR6vc1qbkL8ab6+vvzz\nzz82x54/f87ChQsJDg5Gr9fz5MmTeq/LyckhMDDQbuWQWwZCtDBlZWXExcWRmZmpLDNaVFRkk+bj\nx49kZWWh0+nqvd7BwYHIyEj0ej1msxmtVsvIkSPRaDS/rcweHh4kJycr/yckJBAREYGTkxMAK1as\nsHueqampaDQaZclW+Lld+fR6Pfv27SM2NtaexRPil2zcuJG4uDj69u3L7du3iY2N5dChQ0r8xYsX\nGI1Gxo8fb7c8pUMgRAtTUVGBSqWiY8eOyrHBgwfbpFm2bBl79uwhMDAQlarhZuzm5oaPjw/Pnj2r\nF4uKikKlUvHo0SPevHnD2LFj2bRpE05OTlRUVBATE0NJSQlWq5WIiAh0Oh3V1dXExcVx9epVnJ2d\ncXV1JSUlBaPRSEhICIWFhcqFNSwsDEdHR5KTk4mPj8fHxwe9Xs+HDx/YunWrsh67Vqtl4cKFAMyd\nOxcfHx9u3bpFWVlZvdGRuk6cOMGuXbtsjp0+fZrLly9jNpsJDw9Hr9cDNaMHAQEBDcbi4+NZv349\nzs7OP6oaIf6IDx8+cOvWLVauXKkcqzviBnDmzBn8/f3tunmYdAiEaGEGDx7MsGHDmDx5MmPHjmX0\n6NFotVqbPdC9vb0ZOnQox44dsxmq/1ZpaSk3b95k9uzZ343fvXuX48eP4+zsTGRkJGlpaej1erZu\n3YqXlxcJCQmUl5cTHBzM0KFDqaqq4tq1axgMBgDev39f7z1jYmJISUkhNTVV+fVe90tr7969AGRn\nZ2M2mwkLC2PgwIFMmjQJqNmA5dixY5jNZqZOnUpoaCh9+vSxycNkMlFWVka/fv3qHT958iSvX79G\np9MxZswYZe39b2O+vr54eXnRrl07evfuzZ07d/D19W3wsxTiT7FarXTo0IHMzMwG0xgMBmJiYuya\nr8whEKKFcXBwICEhgcOHDzNu3DguXLjAzJkzlQ1OatOsWrWKAwcO8PHjR5vXW61W9u/fj06nY+nS\npSxatAg/P7/v5jNjxgxcXFxwdHREp9NRWFgIQEFBgdKJ6NatG2q1mqtXr9KnTx++fv1KdHQ0WVlZ\nPzVEX1BQQGhoKFAzghEQEEBBQYES9/f3V2Kenp4UFxfXew+j0ajswldXSEgIAO7u7kyePNlmm9hv\nY9euXVNiPXr0oKSkpMnnIsTv4ObmRq9evcjLywNq2vSDBw+U+OPHj3n79i0jRoywa77SIRCihRow\nYAB6vZ7ExEQ6dOhgcwED6NevH2q1msTERJvjtXMIMjMzycjIYO7cuQ3mUfeCbrVaGxx+rI25ubmR\nk5NDQEAADx8+JCAggNevXzf53L7Nt662bdsqf7dp04bq6uqfft+65/OjmD2HXYVoqjVr1hAWFsbT\np09Rq9VkZGSwfft20tPT0Wq1BAYGkp+fr6Q3GAx2nUxYS24ZCNHClJaW8vLlS0aOHAnUDKGbTCZ6\n9epVL+3y5cuZNWsWFoulyflYrVby8vIIDw/HycmJrKwsZeLhhAkTSEtLY/ny5ZSXl3Px4kUWLFiA\nyWTC0dGRiRMn4ufnx/nz5ykpKaFr1642792+fXvevXtnM+Gv1oQJE0hPT2f06NGYzWYMBgPr1q2z\nKdd/6dmzJ2VlZfWOnzp1ilGjRmEymbh48SLh4eGNir169eq7n68Qf0Lt7oTfOnjw4HeP1+5AaW/S\nIRCihbFYLOzZs4cXL17Qrl07qqurWb16NYMGDaqX1sPDA61WS1JSUpPzcXBwwMfHR7nQjxs3TrlN\nsGHDBjZt2sTMmTOxWq2sXbsWT09P7t+/z4YNG7BYLFgsFtRqNSNGjMBoNNr8yp4/fz7h4eG4uLjY\nPH0AsHTpUrZs2UJQUBBQM6mw7pa6jfm17u7uTrdu3Xj69KnNPIIuXboQHByM2Wxm8eLFDBgwQIl1\n7tz5u7HPnz9TXFzM8OHDm/wZCvF/IgsTCfGXio6OxtvbW5lt39okJSVhNpsb9WtJo9Gwf/9++vfv\nXy+Wm5tLYWEhcXFxv6OYQrQaModACNEqzZkzh/z8fGVhop919OhRlixZYqdSCdF6yQiBEEIIIWSE\nQAghhBDSIRBCCCEE0iEQQgghBNIhEEIIIQTSIRBCCCEE0iEQQgghBPAvphwR5uAxfhAAAAAASUVO\nRK5CYII=\n", 1554 | "text/plain": [ 1555 | "" 1556 | ] 1557 | }, 1558 | "metadata": {}, 1559 | "output_type": "display_data" 1560 | } 1561 | ], 1562 | "source": [ 1563 | "fig, ax = plt.subplots()\n", 1564 | "ax.scatter(sig_snps['start'], sig_snps['chi_squared_score'], alpha=0.5, c='red')\n", 1565 | "ax.set_xlim([3.3e7, 3.5e7])\n", 1566 | "ax.set_ylabel('Chi-squared score')\n", 1567 | "ax.set_xlabel('SNP position (bp)')" 1568 | ] 1569 | }, 1570 | { 1571 | "cell_type": "markdown", 1572 | "metadata": {}, 1573 | "source": [ 1574 | "## Further exploration of statistically significant variant positions" 1575 | ] 1576 | }, 1577 | { 1578 | "cell_type": "markdown", 1579 | "metadata": {}, 1580 | "source": [ 1581 | "We can take our analysis further by mapping selected variant positions back to the chromosome and visualizing call sets and reads. Let's retrieve the top SNP identified when ranked by the Chi-squared score:" 1582 | ] 1583 | }, 1584 | { 1585 | "cell_type": "code", 1586 | "execution_count": 20, 1587 | "metadata": { 1588 | "collapsed": false 1589 | }, 1590 | "outputs": [], 1591 | "source": [ 1592 | "%%sql --module top_snp\n", 1593 | "SELECT start\n", 1594 | "FROM $sig_snps_dataset\n", 1595 | "ORDER BY chi_squared_score desc\n", 1596 | "LIMIT 1" 1597 | ] 1598 | }, 1599 | { 1600 | "cell_type": "code", 1601 | "execution_count": 21, 1602 | "metadata": { 1603 | "collapsed": false 1604 | }, 1605 | "outputs": [ 1606 | { 1607 | "data": { 1608 | "text/html": [ 1609 | "\n", 1610 | "
\n", 1611 | "
(rows: 1, time: 0.5s, cached, job: job_2uTBR9MmYxBWlv4lt3cSdw_dQmM)
\n", 1612 | " \n", 1626 | " " 1627 | ], 1628 | "text/plain": [] 1629 | }, 1630 | "execution_count": 21, 1631 | "metadata": {}, 1632 | "output_type": "execute_result" 1633 | } 1634 | ], 1635 | "source": [ 1636 | "bq.Query(top_snp,\n", 1637 | " sig_snps_dataset=sig_snps_dataset,\n", 1638 | " results=results,\n", 1639 | " grouped_counts=grouped_counts,\n", 1640 | " snps=snps,\n", 1641 | " exp_groups=exp_groups,\n", 1642 | " allele_counts=allele_counts,\n", 1643 | " sample_info_table=sample_info_table,\n", 1644 | " variants_table=variants_table).results()" 1645 | ] 1646 | }, 1647 | { 1648 | "cell_type": "markdown", 1649 | "metadata": {}, 1650 | "source": [ 1651 | "Grab an arbitrary set of 10 callset IDs for rendering in the genome browser." 1652 | ] 1653 | }, 1654 | { 1655 | "cell_type": "code", 1656 | "execution_count": 22, 1657 | "metadata": { 1658 | "collapsed": false 1659 | }, 1660 | "outputs": [], 1661 | "source": [ 1662 | "%%sql --module callset_ids\n", 1663 | "SELECT * FROM (\n", 1664 | " SELECT call.call_set_id AS callset_id\n", 1665 | " FROM $variants_table\n", 1666 | " GROUP BY callset_id)\n", 1667 | "LIMIT 10" 1668 | ] 1669 | }, 1670 | { 1671 | "cell_type": "code", 1672 | "execution_count": 23, 1673 | "metadata": { 1674 | "collapsed": false 1675 | }, 1676 | "outputs": [], 1677 | "source": [ 1678 | "callsets_df = bq.Query(callset_ids, variants_table=variants_table).to_dataframe()\n", 1679 | "callsets = list(callsets_df['callset_id'])" 1680 | ] 1681 | }, 1682 | { 1683 | "cell_type": "code", 1684 | "execution_count": 24, 1685 | "metadata": { 1686 | "collapsed": false 1687 | }, 1688 | "outputs": [], 1689 | "source": [ 1690 | "from IPython.display import HTML\n", 1691 | "def gabrowse(dataset, reference_name, start_position, callset_ids):\n", 1692 | " callsets_query_params = ''.join('&callsetId=%s&cBackend=GOOGLE' % callset_id for callset_id in callset_ids)\n", 1693 | " url = ('https://gabrowse.appspot.com/#=&backend=GOOGLE&location=12%3A'\n", 1694 | " + str(start_position)\n", 1695 | " + callsets_query_params)\n", 1696 | " return HTML('' % url)" 1697 | ] 1698 | }, 1699 | { 1700 | "cell_type": "markdown", 1701 | "metadata": {}, 1702 | "source": [ 1703 | "Now we can render the call sets and reads for the selected SNP position by embedding the GABrowse application directly in our notebook." 1704 | ] 1705 | }, 1706 | { 1707 | "cell_type": "code", 1708 | "execution_count": 25, 1709 | "metadata": { 1710 | "collapsed": false 1711 | }, 1712 | "outputs": [ 1713 | { 1714 | "data": { 1715 | "text/html": [ 1716 | "" 1717 | ], 1718 | "text/plain": [ 1719 | "" 1720 | ] 1721 | }, 1722 | "execution_count": 25, 1723 | "metadata": {}, 1724 | "output_type": "execute_result" 1725 | } 1726 | ], 1727 | "source": [ 1728 | "gabrowse('1000genomes', '12', 110571373, callsets)" 1729 | ] 1730 | }, 1731 | { 1732 | "cell_type": "markdown", 1733 | "metadata": {}, 1734 | "source": [ 1735 | "# Summary" 1736 | ] 1737 | }, 1738 | { 1739 | "cell_type": "markdown", 1740 | "metadata": {}, 1741 | "source": [ 1742 | "This notebook illustrated how to conduct a GWAS experiment using variant data stored within the Google Genomics BigQuery tables, retrieve a local copy of the top results and visualize the data with Python libraries." 1743 | ] 1744 | } 1745 | ], 1746 | "metadata": { 1747 | "kernelspec": { 1748 | "display_name": "Python 2", 1749 | "language": "python", 1750 | "name": "python2" 1751 | }, 1752 | "language_info": { 1753 | "codemirror_mode": { 1754 | "name": "ipython", 1755 | "version": 2 1756 | }, 1757 | "file_extension": ".py", 1758 | "mimetype": "text/x-python", 1759 | "name": "python", 1760 | "nbconvert_exporter": "python", 1761 | "pygments_lexer": "ipython2", 1762 | "version": "2.7.9" 1763 | } 1764 | }, 1765 | "nbformat": 4, 1766 | "nbformat_minor": 0 1767 | } 1768 | -------------------------------------------------------------------------------- /datalab/genomics/Getting started with the Genomics API.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "\n", 12 | "\n", 13 | "\n", 14 | "\n", 15 | "\n", 16 | "\n", 17 | "\n", 18 | "\n", 19 | "\n", 20 | "\n", 21 | "# Getting started with the Google Genomics API" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "In this notebook we'll cover how to make authenticated requests to the [Google Genomics API](https://cloud.google.com/genomics/reference/rest/).\n", 29 | "\n", 30 | "----\n", 31 | "\n", 32 | "NOTE:\n", 33 | "\n", 34 | "* If you're new to notebooks, or want to check out additional samples, check out the full [list](../) of general notebooks.\n", 35 | "* For additional Genomics samples, check out the full [list](./) of Genomics notebooks." 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "## Setup" 43 | ] 44 | }, 45 | { 46 | "cell_type": "markdown", 47 | "metadata": {}, 48 | "source": [ 49 | "### Install Python libraries" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "metadata": {}, 55 | "source": [ 56 | "We'll be using the [Google Python API client](https://github.com/google/google-api-python-client) for interacting with Genomics API. We can install this library, or any other 3rd-party Python libraries from the [Python Package Index (PyPI)](https://pypi.python.org/pypi) using the `pip` package manager.\n", 57 | "\n", 58 | "There are [50+ Google APIs](http://api-python-client-doc.appspot.com/) that you can work against with the Google Python API Client, but we'll focus on the Genomics API in this notebook." 59 | ] 60 | }, 61 | { 62 | "cell_type": "code", 63 | "execution_count": 1, 64 | "metadata": { 65 | "collapsed": false 66 | }, 67 | "outputs": [ 68 | { 69 | "name": "stdout", 70 | "output_type": "stream", 71 | "text": [ 72 | "Requirement already up-to-date: google-api-python-client in /usr/local/lib/python2.7/dist-packages\n", 73 | "Cleaning up...\n" 74 | ] 75 | } 76 | ], 77 | "source": [ 78 | "!pip install --upgrade google-api-python-client" 79 | ] 80 | }, 81 | { 82 | "cell_type": "markdown", 83 | "metadata": {}, 84 | "source": [ 85 | "### Create an Authenticated Client" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "Next we construct a Python object that we can use it to make requests. \n", 93 | "\n", 94 | "The following snippet shows how we can authenticate using the service account on the Datalab host. For more detail about authentication from Python, see [Using OAuth 2.0 for Server to Server Applications](https://developers.google.com/api-client-library/python/auth/service-accounts)." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 2, 100 | "metadata": { 101 | "collapsed": false 102 | }, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "text/plain": [ 107 | "" 108 | ] 109 | }, 110 | "execution_count": 2, 111 | "metadata": {}, 112 | "output_type": "execute_result" 113 | }, 114 | { 115 | "data": { 116 | "text/plain": [ 117 | "" 118 | ] 119 | }, 120 | "execution_count": 2, 121 | "metadata": {}, 122 | "output_type": "execute_result" 123 | } 124 | ], 125 | "source": [ 126 | "from httplib2 import Http\n", 127 | "from oauth2client.client import GoogleCredentials\n", 128 | "credentials = GoogleCredentials.get_application_default()\n", 129 | "http = Http()\n", 130 | "credentials.authorize(http)\n" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "metadata": {}, 136 | "source": [ 137 | "And then we create a client for the Genomics API." 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 3, 143 | "metadata": { 144 | "collapsed": false 145 | }, 146 | "outputs": [], 147 | "source": [ 148 | "from apiclient.discovery import build\n", 149 | "genomics = build('genomics', 'v1', http=http)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "### Send a request to the Genomics API" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "Now that we have a Python client for the Genomics API, we can access a variety of different resources. For details about each available resource, see the python client [API docs here](https://google-api-client-libraries.appspot.com/documentation/genomics/v1/python/latest/index.html).\n", 164 | "\n", 165 | "Using our `genomics` client, we'll demonstrate fetching a Dataset resource by ID (the [1000 Genomes dataset](http://googlegenomics.readthedocs.org/en/latest/use_cases/discover_public_data/1000_genomes.html) in this case).\n", 166 | "\n", 167 | "First, we need to construct a request object." 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 4, 173 | "metadata": { 174 | "collapsed": false 175 | }, 176 | "outputs": [], 177 | "source": [ 178 | "request = genomics.datasets().get(datasetId='10473108253681171589')" 179 | ] 180 | }, 181 | { 182 | "cell_type": "markdown", 183 | "metadata": {}, 184 | "source": [ 185 | "Next, we'll send this request to the Genomics API by calling the `request.execute()` method." 186 | ] 187 | }, 188 | { 189 | "cell_type": "code", 190 | "execution_count": 5, 191 | "metadata": { 192 | "collapsed": false 193 | }, 194 | "outputs": [], 195 | "source": [ 196 | "response = request.execute()" 197 | ] 198 | }, 199 | { 200 | "cell_type": "markdown", 201 | "metadata": {}, 202 | "source": [ 203 | "You will need enable the Genomics API for your project if you have not done so previously. Click on [this link](https://console.developers.google.com/flows/enableapi?apiid=genomics) to enable the API in your project." 204 | ] 205 | }, 206 | { 207 | "cell_type": "markdown", 208 | "metadata": {}, 209 | "source": [ 210 | "The response object returned is simply a Python dictionary. Let's take a look at the properties returned in the response." 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 6, 216 | "metadata": { 217 | "collapsed": false 218 | }, 219 | "outputs": [ 220 | { 221 | "name": "stdout", 222 | "output_type": "stream", 223 | "text": [ 224 | "projectId => genomics-public-data\n", 225 | "id => 10473108253681171589\n", 226 | "createTime => 1970-01-01T00:00:00.000Z\n", 227 | "name => 1000 Genomes\n" 228 | ] 229 | } 230 | ], 231 | "source": [ 232 | "for entry in response.items():\n", 233 | " print \"%s => %s\" % entry" 234 | ] 235 | }, 236 | { 237 | "cell_type": "markdown", 238 | "metadata": {}, 239 | "source": [ 240 | "Success! We can see the name of the specified Dataset and a few other pieces of metadata.\n", 241 | "\n", 242 | "Accessing other Genomics API resources will follow this same set of steps. The full [list of available resources within the API is here](https://google-api-client-libraries.appspot.com/documentation/genomics/v1/python/latest/index.html). Each resource has details about the different verbs that can be applied (e.g., [Dataset methods](https://google-api-client-libraries.appspot.com/documentation/genomics/v1/python/latest/genomics_v1.datasets.html))." 243 | ] 244 | }, 245 | { 246 | "cell_type": "markdown", 247 | "metadata": {}, 248 | "source": [ 249 | "## Access Data" 250 | ] 251 | }, 252 | { 253 | "cell_type": "markdown", 254 | "metadata": {}, 255 | "source": [ 256 | "In this portion of the notebook, we implement [this same example](https://github.com/googlegenomics/getting-started-with-the-api/tree/master/python) implemented as a python script. First let's define a few constants to use within the examples that follow." 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": 7, 262 | "metadata": { 263 | "collapsed": false 264 | }, 265 | "outputs": [], 266 | "source": [ 267 | "dataset_id = '10473108253681171589' # This is the 1000 Genomes dataset ID\n", 268 | "sample = 'NA12872'\n", 269 | "reference_name = '22'\n", 270 | "reference_position = 51003835" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "### Get read bases for a sample at specific a position" 278 | ] 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": {}, 283 | "source": [ 284 | "First find the read group set ID for the sample." 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 8, 290 | "metadata": { 291 | "collapsed": false 292 | }, 293 | "outputs": [], 294 | "source": [ 295 | "request = genomics.readgroupsets().search(\n", 296 | " body={'datasetIds': [dataset_id], 'name': sample},\n", 297 | " fields='readGroupSets(id)')\n", 298 | "read_group_sets = request.execute().get('readGroupSets', [])\n", 299 | "if len(read_group_sets) != 1:\n", 300 | " raise Exception('Searching for %s didn\\'t return '\n", 301 | " 'the right number of read group sets' % sample)\n", 302 | "\n", 303 | "read_group_set_id = read_group_sets[0]['id']" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "metadata": {}, 309 | "source": [ 310 | "Once we have the read group set ID, lookup the reads at the position in which we are interested." 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 9, 316 | "metadata": { 317 | "collapsed": false 318 | }, 319 | "outputs": [], 320 | "source": [ 321 | "request = genomics.reads().search(\n", 322 | " body={'readGroupSetIds': [read_group_set_id],\n", 323 | " 'referenceName': reference_name,\n", 324 | " 'start': reference_position,\n", 325 | " 'end': reference_position + 1,\n", 326 | " 'pageSize': 1024},\n", 327 | " fields='alignments(alignment,alignedSequence)')\n", 328 | "reads = request.execute().get('alignments', [])" 329 | ] 330 | }, 331 | { 332 | "cell_type": "markdown", 333 | "metadata": {}, 334 | "source": [ 335 | "And we print out the results." 336 | ] 337 | }, 338 | { 339 | "cell_type": "code", 340 | "execution_count": 10, 341 | "metadata": { 342 | "collapsed": false 343 | }, 344 | "outputs": [ 345 | { 346 | "name": "stdout", 347 | "output_type": "stream", 348 | "text": [ 349 | "NA12872 bases on 22 at 51003835 are\n", 350 | "C: 1\n", 351 | "G: 13\n" 352 | ] 353 | } 354 | ], 355 | "source": [ 356 | "# Note: This is simplistic - the cigar should be considered for real code\n", 357 | "bases = [read['alignedSequence'][\n", 358 | " reference_position - int(read['alignment']['position']['position'])]\n", 359 | " for read in reads]\n", 360 | "\n", 361 | "print '%s bases on %s at %d are' % (sample, reference_name, reference_position)\n", 362 | "\n", 363 | "from collections import Counter\n", 364 | "for base, count in Counter(bases).items():\n", 365 | " print '%s: %s' % (base, count)" 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": {}, 371 | "source": [ 372 | "### Get variants for a sample at specific a position" 373 | ] 374 | }, 375 | { 376 | "cell_type": "markdown", 377 | "metadata": {}, 378 | "source": [ 379 | "First find the call set ID for the sample." 380 | ] 381 | }, 382 | { 383 | "cell_type": "code", 384 | "execution_count": 11, 385 | "metadata": { 386 | "collapsed": false 387 | }, 388 | "outputs": [], 389 | "source": [ 390 | "request = genomics.callsets().search(\n", 391 | " body={'variantSetIds': [dataset_id], 'name': sample},\n", 392 | " fields='callSets(id)')\n", 393 | "resp = request.execute()\n", 394 | "call_sets = resp.get('callSets', [])\n", 395 | "if len(call_sets) != 1:\n", 396 | " raise Exception('Searching for %s didn\\'t return '\n", 397 | " 'the right number of call sets' % sample)\n", 398 | "\n", 399 | "call_set_id = call_sets[0]['id']" 400 | ] 401 | }, 402 | { 403 | "cell_type": "markdown", 404 | "metadata": {}, 405 | "source": [ 406 | "Once we have the call set ID, lookup the variants that overlap the position in which we are interested." 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 12, 412 | "metadata": { 413 | "collapsed": false 414 | }, 415 | "outputs": [], 416 | "source": [ 417 | "request = genomics.variants().search(\n", 418 | " body={'callSetIds': [call_set_id],\n", 419 | " 'referenceName': reference_name,\n", 420 | " 'start': reference_position,\n", 421 | " 'end': reference_position + 1},\n", 422 | " fields='variants(names,referenceBases,alternateBases,calls(genotype))')\n", 423 | "variant = request.execute().get('variants', [])[0]" 424 | ] 425 | }, 426 | { 427 | "cell_type": "markdown", 428 | "metadata": {}, 429 | "source": [ 430 | "And we print out the results." 431 | ] 432 | }, 433 | { 434 | "cell_type": "code", 435 | "execution_count": 13, 436 | "metadata": { 437 | "collapsed": false 438 | }, 439 | "outputs": [ 440 | { 441 | "name": "stdout", 442 | "output_type": "stream", 443 | "text": [ 444 | "the called genotype is G,G for rs131767\n" 445 | ] 446 | } 447 | ], 448 | "source": [ 449 | "variant_name = variant['names'][0]\n", 450 | "genotype = [variant['referenceBases'] if g == 0\n", 451 | " else variant['alternateBases'][g - 1]\n", 452 | " for g in variant['calls'][0]['genotype']]\n", 453 | "\n", 454 | "print 'the called genotype is %s for %s' % (','.join(genotype), variant_name)" 455 | ] 456 | } 457 | ], 458 | "metadata": { 459 | "kernelspec": { 460 | "display_name": "Python 2", 461 | "language": "python", 462 | "name": "python2" 463 | }, 464 | "language_info": { 465 | "codemirror_mode": { 466 | "name": "ipython", 467 | "version": 2 468 | }, 469 | "file_extension": ".py", 470 | "mimetype": "text/x-python", 471 | "name": "python", 472 | "nbconvert_exporter": "python", 473 | "pygments_lexer": "ipython2", 474 | "version": "2.7.9" 475 | } 476 | }, 477 | "nbformat": 4, 478 | "nbformat_minor": 0 479 | } 480 | --------------------------------------------------------------------------------