From 02e55c208dd130e1c265d45216fc470a931e0349 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 7 Oct 2020 15:13:07 -0400 Subject: [PATCH 01/50] Adding in some style with css --- components/styles.css | 24 ++++++++++++++++++++++++ scripts/render-notebooks.R | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 components/styles.css diff --git a/components/styles.css b/components/styles.css new file mode 100644 index 00000000..ab415cbe --- /dev/null +++ b/components/styles.css @@ -0,0 +1,24 @@ +p { + color: blue; + font-family: Lato,sans-serif; +} + +h1 { + color: blue; + font-family: Lato,sans-serif; +} + +h2 { + color: blue; + font-family: Lato,sans-serif; +} + +h3 { + color: blue; + font-family: Lato,sans-serif; +} + +h4 { + color: blue; + font-family: Lato,sans-serif; +} diff --git a/scripts/render-notebooks.R b/scripts/render-notebooks.R index 54dfabf2..8e9d54c0 100644 --- a/scripts/render-notebooks.R +++ b/scripts/render-notebooks.R @@ -111,7 +111,8 @@ readr::write_lines(new_lines, tmp_file) rmarkdown::render(tmp_file, output_format = rmarkdown::html_document( toc = TRUE, toc_depth = 2, - toc_float = TRUE, number_sections = TRUE + toc_float = TRUE, number_sections = TRUE, + css = file.path("..", "components", "styles.css") ), # Save to original html output file name output_file = output_file From 9e703448263fe92e7639c9e9f094572d713ae007 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 7 Oct 2020 17:04:45 -0400 Subject: [PATCH 02/50] Use css magic --- components/styles.css | 50 ++++++++++++++++++++++++++++++------------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/components/styles.css b/components/styles.css index ab415cbe..2818314c 100644 --- a/components/styles.css +++ b/components/styles.css @@ -1,24 +1,44 @@ -p { - color: blue; - font-family: Lato,sans-serif; +html, +body { + font-family: 'Lato', sans-serif; + font-size: 14px; + -webkit-font-smoothing: antialiased; + line-height: 1.5; +} +h1, h2, h3, h4, h5, h6 { + font-family: 'Rubik', sans-serif; } - h1 { - color: blue; - font-family: Lato,sans-serif; + font-size: 1.625rem; } - h2 { - color: blue; - font-family: Lato,sans-serif; + font-size: 1.375rem; } - h3 { - color: blue; - font-family: Lato,sans-serif; + font-size: 1.25rem } - h4 { - color: blue; - font-family: Lato,sans-serif; + font-size: 1.125rem; +} +h5, h6 { + font-size: 1rem +} +p { + font-size: 1rem; + margin: 0 0 0.5rem 0; + line-height: 1.5; +} +a { + text-decoration: none; + color: #386db0; + line-height: 1; +} +.navbar-default { + background-color: white !important; +} +.navbar-brand, nav a { + color: #386db0 !important; +} +.list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { + background-color: #386db0 !important; } From a7aad2f80ba7c3ec315e39f31883f7ecaf16f148 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 7 Oct 2020 17:22:59 -0400 Subject: [PATCH 03/50] Try making the navbar blue --- components/styles.css | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/styles.css b/components/styles.css index 2818314c..65b6c2ab 100644 --- a/components/styles.css +++ b/components/styles.css @@ -34,10 +34,16 @@ a { line-height: 1; } .navbar-default { - background-color: white !important; + font-size: 1.625rem; + background-color: #002F6C !important; + color: #FDFDFD; } .navbar-brand, nav a { - color: #386db0 !important; + color: #FDFDFD !important; +} +ul.dropdown-menu { + background-color: #002F6C !important; + color: #FDFDFD; } .list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { background-color: #386db0 !important; From 3927752a410271ade59e3e437b4a276eac4d6bc0 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Thu, 15 Oct 2020 10:16:33 -0400 Subject: [PATCH 04/50] Add survey link --- components/_navbar.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/_navbar.html b/components/_navbar.html index 6b8d0b96..fca336fd 100644 --- a/components/_navbar.html +++ b/components/_navbar.html @@ -60,7 +60,7 @@ From 8d7b8e23b36a0bc65abd6b9153a5e4eb354e6c16 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Thu, 15 Oct 2020 10:29:57 -0400 Subject: [PATCH 05/50] Make font smaller --- 02-microarray/00-intro-to-microarray.html | 62 ++++++++++++++++++++++- components/_navbar.html | 2 +- components/styles.css | 2 +- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/02-microarray/00-intro-to-microarray.html b/02-microarray/00-intro-to-microarray.html index 129c657d..f5a0d941 100644 --- a/02-microarray/00-intro-to-microarray.html +++ b/02-microarray/00-intro-to-microarray.html @@ -1283,6 +1283,15 @@ + + + @@ -1653,7 +1713,7 @@ diff --git a/components/_navbar.html b/components/_navbar.html index fca336fd..4f53dee6 100644 --- a/components/_navbar.html +++ b/components/_navbar.html @@ -60,8 +60,8 @@ diff --git a/components/styles.css b/components/styles.css index 65b6c2ab..031248dd 100644 --- a/components/styles.css +++ b/components/styles.css @@ -34,7 +34,7 @@ a { line-height: 1; } .navbar-default { - font-size: 1.625rem; + font-size: 1.5rem; background-color: #002F6C !important; color: #FDFDFD; } From b0ced0fcba1944a713e6af9d89c7dd04ef506e40 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Thu, 15 Oct 2020 13:26:36 -0400 Subject: [PATCH 06/50] Need a comma --- components/styles.css | 2 +- scripts/render-notebooks.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/styles.css b/components/styles.css index 031248dd..7a181d4d 100644 --- a/components/styles.css +++ b/components/styles.css @@ -34,7 +34,7 @@ a { line-height: 1; } .navbar-default { - font-size: 1.5rem; + font-size: 1rem; background-color: #002F6C !important; color: #FDFDFD; } diff --git a/scripts/render-notebooks.R b/scripts/render-notebooks.R index 936308e9..7e25ab19 100644 --- a/scripts/render-notebooks.R +++ b/scripts/render-notebooks.R @@ -112,7 +112,7 @@ rmarkdown::render(tmp_file, output_format = rmarkdown::html_document( toc = TRUE, toc_depth = 2, toc_float = TRUE, number_sections = TRUE, - df_print = "paged" + df_print = "paged", css = file.path("..", "components", "styles.css") ), # Save to original html output file name From de9726b534edeafaebfdc6bd5969a0a9bcac40df Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Mon, 19 Oct 2020 07:53:10 -0400 Subject: [PATCH 07/50] Change to normalizePath --- components/styles.css | 9 +++++---- scripts/render-notebooks.R | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/components/styles.css b/components/styles.css index 7a181d4d..9a8f50c1 100644 --- a/components/styles.css +++ b/components/styles.css @@ -35,16 +35,17 @@ a { } .navbar-default { font-size: 1rem; - background-color: #002F6C !important; + background-color: #386db0 !important; color: #FDFDFD; } .navbar-brand, nav a { - color: #FDFDFD !important; + color: #000000 !important; } ul.dropdown-menu { - background-color: #002F6C !important; - color: #FDFDFD; + background-color: #FDFDFD !important; + color: #000000 !important; } .list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { background-color: #386db0 !important; + color: #000000 !important; } diff --git a/scripts/render-notebooks.R b/scripts/render-notebooks.R index 7e25ab19..7848de2b 100644 --- a/scripts/render-notebooks.R +++ b/scripts/render-notebooks.R @@ -113,7 +113,7 @@ rmarkdown::render(tmp_file, toc = TRUE, toc_depth = 2, toc_float = TRUE, number_sections = TRUE, df_print = "paged", - css = file.path("..", "components", "styles.css") + css = normalizePath(file.path("components", "styles.css")) ), # Save to original html output file name output_file = output_file From 69280567afe99cfb9f12db585898696fbc8d2e52 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Mon, 19 Oct 2020 08:05:31 -0400 Subject: [PATCH 08/50] normalizepath separate step references.bib --- scripts/render-notebooks.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/render-notebooks.R b/scripts/render-notebooks.R index 7848de2b..cdb5057c 100644 --- a/scripts/render-notebooks.R +++ b/scripts/render-notebooks.R @@ -54,6 +54,9 @@ opt <- parse_args(OptionParser(option_list = option_list)) # Get working directory base_dir <- getwd() +# Normalize file path +opt$bib_file <- normalizePath(opt$bib_file) + # Check that the rmd file exists if (!file.exists(opt$rmd)) { stop("Rmd file specified with --rmd is not found.") @@ -63,7 +66,7 @@ if (!file.exists(opt$rmd)) { if (!file.exists(opt$bib_file)) { stop("File specified for --bib_file option is not at the specified file path.") } else { - header_line <- paste("bibliography:", normalizePath(opt$bib_file)) + header_line <- paste("bibliography:", opt$bib_file) } # Check for a citation style if (!is.null(opt$cite_style)){ From 4c07c284068c49ad4810060162b3092aae4439c3 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Mon, 19 Oct 2020 08:07:50 -0400 Subject: [PATCH 09/50] Move references.bib to component folder --- CONTRIBUTING.md | 4 ++-- Snakefile | 2 +- references.bib => components/references.bib | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename references.bib => components/references.bib (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 429acf3d..1ef5ca91 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -289,7 +289,7 @@ The `Snakefile` calls the `scripts/render-notebooks.R` which renders the `.html` However, the `snakemake` workflow should also be run locally during development so that the author and reviewers can see the rendered output of the new material during the `Pull Request` process. Ideally snakemake will not re-render the `.html` for `.Rmd` files you have not edited, but if it does, you should only commit and push the files you have intended to change. -All `.html` files will be re-rendered upon merging to master, but by not committing files that are only altered incidentally, the `Files changed` page of your PR on GitHub will be more focused, easing the burden on reviewers. +All `.html` files will be re-rendered upon merging to master, but by not committing files that are only altered incidentally, the `Files changed` page of your PR on GitHub will be more focused, easing the burden on reviewers. ### How to re-render the notebooks locally @@ -332,7 +332,7 @@ The `render-notebooks.R` script adds a `bibliography:` specification in the `.Rm **Options:** - `--rmd`: provided by snakemake, the input `.Rmd` file to render. - `--bib_file`: File path for the `bibliography:` header option. -Default is the `references.bib` script at the top of the repository. +Default is the `references.bib` in the `components` folder. - `--html`: Default is to save the output `.html` file the same name as the input `.Rmd` file. This option allows you to specify an output file name. Default is used by snakemake. ### Add new analyses to the Snakefile diff --git a/Snakefile b/Snakefile index 60ca9dcd..4909b910 100644 --- a/Snakefile +++ b/Snakefile @@ -27,7 +27,7 @@ rule render_citations: shell: "Rscript scripts/render-notebooks.R" " --rmd {input.rmd}" - " --bib_file references.bib" + " --bib_file components/references.bib" " --cite_style components/genetics.csl" " --html {output}" " --style" diff --git a/references.bib b/components/references.bib similarity index 100% rename from references.bib rename to components/references.bib From fa1453822a5ebecdae1e63267f0cb5824cf22f44 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 21 Oct 2020 16:17:41 -0400 Subject: [PATCH 10/50] Update github actions to reflect staging branch (#311) * Update github actions to reflect staging branch * Add libglpk40 to Dockerfile * Make it gh-pages-stages! * Remove dockerfile change that should have been on its own all along * Does this work? * Declare a uses * Switch how env is declared * Force it to run so we can test it * try no curly brackets * What's up with the branch * Move to bash if instead * Need quotes? * forgot a `then` * Try dollar signs * Doesn't like the `.`? * Use curly brackets * Try ${GITHUB_REF} * Try ${BRANCH_NAME} * try ${GITHUB_REF#refs/*/} * use jashapiro suggestion * Change to base ref * Change back to `github.ref` * Get rid of PR `on:` * Try another test * Docker dep fix: Add lib package 40 thing that clusterprofiler needs (#316) * Add lib package 40 thing that clusterprofiler needs * Try adding options(warn = 2) * Test if options(warn =2) means it breaks like it should * Revert "Test if options(warn =2) means it breaks like it should" This reverts commit d9f688f68448ef69fe4c1caa48af23051cd7f4e3. * Revert "Try another test" This reverts commit 845cf1aff92ea7b83f402bbefd563562b44e5eac. --- .github/workflows/docker-build-push.yml | 32 ++++++++++++++++++------ .github/workflows/docker-build.yml | 4 +-- .github/workflows/style-and-sp-check.yml | 2 +- docker/Dockerfile | 5 ++-- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 47cc48fd..f157eb03 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -4,7 +4,7 @@ name: Build, Render, and Push # events only for the master branch on: push: - branches: [ master ] + branches: [ staging, master ] jobs: # This workflow contains a single job called "build-all" @@ -21,11 +21,20 @@ jobs: fetch-depth: 0 # use alexslemonade-docs-bot token: ${{ secrets.DOCS_BOT_GITHUB_TOKEN }} + - name: Checkout pages branch and sync with changes run: | + echo $GITHUB_REF + if [ $GITHUB_REF == 'refs/heads/master' ] + then + pages_branch="gh-pages" + elif [ $GITHUB_REF == 'refs/heads/staging' ] + then + pages_branch="gh-pages-stages" + fi git config --local user.email "actions@github.com" git config --local user.name "Alex's Lemonade Docs Bot" - git checkout gh-pages + git checkout $pages_branch git merge -s recursive --strategy-option=theirs ${{ github.event.after }} # Test if Dockerfile has changed @@ -68,7 +77,7 @@ jobs: # download data - name: Download data run: bash scripts/download-data.sh - + - name: Render all pages to html run: | docker run \ @@ -76,11 +85,18 @@ jobs: ccdl/refinebio-examples \ snakemake --cores 2 --forceall - - name: Commit changed html + # If we are on the staging branch, do not publish to github pages + - name: Commit changed html back to non-public pages + if: github.ref == 'refs/heads/staging' run: | git add -A - git commit -m 'Render html' || echo "No changes to commit" - git push origin gh-pages || echo "No changes to push" - - + git commit -m 'Render html, do not publish' || echo "No changes to commit" + git push origin gh-pages-stages || echo "No changes to push" + # If we are on the master branch, publish to github pages! + - name: Commit changed html to public pages + if: github.ref == 'refs/heads/master' + run: | + git add -A + git commit -m 'Render html and publish' || echo "No changes to commit" + git push origin gh-pages || echo "No changes to push" diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index e5da75b0..aa065d43 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -1,10 +1,10 @@ name: Build Docker -# Controls when the action will run. Triggers the workflow for a pull request for +# Controls when the action will run. Triggers the workflow for a pull request for # master on: pull_request: - branches: [ master ] + branches: [ staging, master ] paths: [ docker/Dockerfile ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel diff --git a/.github/workflows/style-and-sp-check.yml b/.github/workflows/style-and-sp-check.yml index cf536f9e..314b12eb 100644 --- a/.github/workflows/style-and-sp-check.yml +++ b/.github/workflows/style-and-sp-check.yml @@ -5,7 +5,7 @@ name: Style and spell check R markdowns # events but only for the master branch on: pull_request: - branches: [ master ] + branches: [ staging, master ] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: diff --git a/docker/Dockerfile b/docker/Dockerfile index 570a66e2..89ab3b16 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -14,7 +14,8 @@ RUN apt-get update -qq && apt-get -y --no-install-recommends install \ zlib1g \ libbz2-dev \ liblzma-dev \ - libreadline-dev + libreadline-dev \ + libglpk40 # libmagick++-dev is needed for coloblindr to install RUN apt-get -y --no-install-recommends install \ @@ -48,7 +49,7 @@ RUN Rscript -e "install.packages( \ # Install bioconductor packages # org.Mm.eg.db and org.Dr.eg.db are required for gene mapping -RUN R -e "BiocManager::install( \ +RUN R -e "options(warn = 2); BiocManager::install( \ c('affy', \ 'apeglm', \ 'Biobase', \ From 4ab1d802c59d3fc0d2963f5c5ad0857e119209c7 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 21 Oct 2020 16:18:20 -0400 Subject: [PATCH 11/50] Add google analytics to renderings (#314) * Try adding google analytics * Add to header using includes * temporary file snuck in there * Restore master version so they aren't in the review * Let's call an html file and html file * Docker dep fix: Add lib package 40 thing that clusterprofiler needs (#316) * Add lib package 40 thing that clusterprofiler needs * Try adding options(warn = 2) * Test if options(warn =2) means it breaks like it should * Revert "Test if options(warn =2) means it breaks like it should" This reverts commit d9f688f68448ef69fe4c1caa48af23051cd7f4e3. --- components/google-analytics.html | 8 ++++++++ scripts/render-notebooks.R | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 components/google-analytics.html diff --git a/components/google-analytics.html b/components/google-analytics.html new file mode 100644 index 00000000..178b08d7 --- /dev/null +++ b/components/google-analytics.html @@ -0,0 +1,8 @@ + + + diff --git a/scripts/render-notebooks.R b/scripts/render-notebooks.R index 3e9e2861..15d4df47 100644 --- a/scripts/render-notebooks.R +++ b/scripts/render-notebooks.R @@ -107,13 +107,17 @@ new_lines <- append(lines, header_line, header_range[1]) # Write to an tmp file readr::write_lines(new_lines, tmp_file) +# Declare path to google analytics bit +google_analytics_file <- normalizePath(file.path("components", "google-analytics.html")) + # Render the header added notebook rmarkdown::render(tmp_file, output_format = rmarkdown::html_document( toc = TRUE, toc_depth = 2, toc_float = TRUE, number_sections = TRUE, df_print = "paged", - highlight = "haddock" + highlight = "haddock", + includes = rmarkdown::includes(in_header = google_analytics_file) ), # Save to original html output file name output_file = output_file From 1f2546c7a8f41c1e242ac470899ae31a1e3c4689 Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 16:40:23 -0400 Subject: [PATCH 12/50] Only push if we are in master. For simplicity, we will now run this even if the dockerfile hasn't changed. --- .github/workflows/docker-build-push.yml | 34 ++++++++++--------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index f157eb03..eedb4c2e 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -37,43 +37,35 @@ jobs: git checkout $pages_branch git merge -s recursive --strategy-option=theirs ${{ github.event.after }} - # Test if Dockerfile has changed - # sets steps.check_docker.outputs.changed to 1 if the Dockerfile has changed, 0 otherwise - - name: Check Dockerfile for changes - id: check_docker - env: - BEFORE: ${{ github.event.before }} - run: | - git diff-index --name-only $BEFORE > changes.txt - if grep "docker/Dockerfile" changes.txt ; then - echo "Dockerfile changed" - echo "::set-output name=changed::1" - else - echo "No change to Dockerfile" - echo "::set-output name=changed::0" - fi - rm changes.txt - # Login to Dockerhub - name: Login to DockerHub - if: steps.check_docker.outputs.changed == 1 uses: docker/login-action@v1 with: username: ${{ secrets.DOCKER_ID }} password: ${{ secrets.DOCKER_PASSWORD }} # set up Docker build - name: Set up Docker Buildx - if: steps.check_docker.outputs.changed == 1 uses: docker/setup-buildx-action@v1 - # Build docker image (We are not using caching here to force a clean build) + + # Build docker image and push if this is master - name: Build and Push Docker image - if: steps.check_docker.outputs.changed == 1 + if: github.ref == 'refs/heads/master' uses: docker/build-push-action@v2 with: push: true context: docker file: docker/Dockerfile tags: ccdl/refinebio-examples:latest + # for staging, we just want to build, but not push + - name: Build and Load Docker image + if: github.ref == 'refs/heads/staging' + uses: docker/build-push-action@v2 + with: + push: false + load: true + context: docker + file: docker/Dockerfile + tags: ccdl/refinebio-examples:latest # download data - name: Download data run: bash scripts/download-data.sh From 7d7ecc1aec1f87ee3ab7ac2bceb854079a12ca8d Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 16:41:21 -0400 Subject: [PATCH 13/50] Add test target --- .github/workflows/docker-build-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index eedb4c2e..c3029142 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -4,7 +4,7 @@ name: Build, Render, and Push # events only for the master branch on: push: - branches: [ staging, master ] + branches: [ staging, master, jashapiro/dont-push-staging-docker ] jobs: # This workflow contains a single job called "build-all" From b96130ee9f057620cb0c123714e8a9a158c1113e Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 16:43:36 -0400 Subject: [PATCH 14/50] test staging workflow with this branch --- .github/workflows/docker-build-push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index c3029142..e3b050c8 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -58,14 +58,14 @@ jobs: tags: ccdl/refinebio-examples:latest # for staging, we just want to build, but not push - name: Build and Load Docker image - if: github.ref == 'refs/heads/staging' + if: github.ref == 'refs/heads/jashapiro/dont-push-staging-docker' uses: docker/build-push-action@v2 with: push: false load: true context: docker file: docker/Dockerfile - tags: ccdl/refinebio-examples:latest + tags: ccdl/refinebio-examples:staging # download data - name: Download data run: bash scripts/download-data.sh From a0640eb807172e141db578651ac7de59564537c7 Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 17:06:02 -0400 Subject: [PATCH 15/50] back to latest tag --- .github/workflows/docker-build-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index e3b050c8..2373e971 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -65,7 +65,7 @@ jobs: load: true context: docker file: docker/Dockerfile - tags: ccdl/refinebio-examples:staging + tags: ccdl/refinebio-examples:latest # download data - name: Download data run: bash scripts/download-data.sh From 8afc962f1ceb20731d935ad5a26c5e1e1dafb4c4 Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 17:29:46 -0400 Subject: [PATCH 16/50] Try separate push step --- .github/workflows/docker-build-push.yml | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 2373e971..e8a29d42 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -46,19 +46,8 @@ jobs: # set up Docker build - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - - # Build docker image and push if this is master - - name: Build and Push Docker image - if: github.ref == 'refs/heads/master' - uses: docker/build-push-action@v2 - with: - push: true - context: docker - file: docker/Dockerfile - tags: ccdl/refinebio-examples:latest - # for staging, we just want to build, but not push + # Build the Docker image - name: Build and Load Docker image - if: github.ref == 'refs/heads/jashapiro/dont-push-staging-docker' uses: docker/build-push-action@v2 with: push: false @@ -66,10 +55,14 @@ jobs: context: docker file: docker/Dockerfile tags: ccdl/refinebio-examples:latest + # push the Docker image if this is master + - name: Push Docker image + if: github.ref == 'refs/heads/master' + run: docker push ccdl/refinebio-examples:latest + # download data - name: Download data run: bash scripts/download-data.sh - - name: Render all pages to html run: | docker run \ From 6a38574d312cee82c90c3c036ac9033f9af7f7ec Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 17:32:34 -0400 Subject: [PATCH 17/50] change tags to test push --- .github/workflows/docker-build-push.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index e8a29d42..2dd0e581 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -54,11 +54,13 @@ jobs: load: true context: docker file: docker/Dockerfile - tags: ccdl/refinebio-examples:latest + tags: | + ccdl/refinebio-examples:latest + ccdl/refinebio-examples:test # push the Docker image if this is master - name: Push Docker image - if: github.ref == 'refs/heads/master' - run: docker push ccdl/refinebio-examples:latest + if: github.ref == 'refs/heads/jashapiro/dont-push-staging-docker' + run: docker push ccdl/refinebio-examples:test # download data - name: Download data From f71bccc43fa308ebbe581d1ea2984ff3ca3dbc7e Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 17:32:34 -0400 Subject: [PATCH 18/50] Revert "change tags to test push" This reverts commit 6a38574d312cee82c90c3c036ac9033f9af7f7ec. --- .github/workflows/docker-build-push.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index 2dd0e581..e8a29d42 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -54,13 +54,11 @@ jobs: load: true context: docker file: docker/Dockerfile - tags: | - ccdl/refinebio-examples:latest - ccdl/refinebio-examples:test + tags: ccdl/refinebio-examples:latest # push the Docker image if this is master - name: Push Docker image - if: github.ref == 'refs/heads/jashapiro/dont-push-staging-docker' - run: docker push ccdl/refinebio-examples:test + if: github.ref == 'refs/heads/master' + run: docker push ccdl/refinebio-examples:latest # download data - name: Download data From 9de0042727b03214988de2e0c3b884ec5c5a2f6e Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Wed, 21 Oct 2020 17:57:34 -0400 Subject: [PATCH 19/50] Remove this branch from triggers --- .github/workflows/docker-build-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index e8a29d42..ff69ab6d 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -4,7 +4,7 @@ name: Build, Render, and Push # events only for the master branch on: push: - branches: [ staging, master, jashapiro/dont-push-staging-docker ] + branches: [ staging, master ] jobs: # This workflow contains a single job called "build-all" From 28e72efbe3cc3999cccf9e0f1100df416c3ab7cb Mon Sep 17 00:00:00 2001 From: Joshua Shapiro Date: Thu, 22 Oct 2020 09:10:00 -0400 Subject: [PATCH 20/50] Push staging, retag and push master Okay, so the branch name is now inaccurate, but that is fine... --- .github/workflows/docker-build-push.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-build-push.yml b/.github/workflows/docker-build-push.yml index ff69ab6d..b3832343 100644 --- a/.github/workflows/docker-build-push.yml +++ b/.github/workflows/docker-build-push.yml @@ -55,10 +55,16 @@ jobs: context: docker file: docker/Dockerfile tags: ccdl/refinebio-examples:latest - # push the Docker image if this is master + # push the Docker image if this is staging - name: Push Docker image - if: github.ref == 'refs/heads/master' + if: github.ref == 'refs/heads/staging' run: docker push ccdl/refinebio-examples:latest + # retag and push the Docker image if this is master + - name: Push release Docker image + if: github.ref == 'refs/heads/master' + run: | + docker tag ccdl/refinebio-examples:latest ccdl/refinebio-examples:release + docker push ccdl/refinebio-examples:release # download data - name: Download data From a660e89593690cac0113fb4f1cb8709c159ef624 Mon Sep 17 00:00:00 2001 From: dvenprasad Date: Thu, 22 Oct 2020 09:58:11 -0400 Subject: [PATCH 21/50] Made ccs modifications, added logo file Made changes to css/navbar.html Tried to add the logo but it but it cuts out and not sure how to make it decent. --- 02-microarray/00-intro-to-microarray.html | 68 ++++++++++++++--------- components/_navbar.html | 24 +++++--- components/refine-bio-ex-logo.svg | 57 +++++++++++++++++++ components/styles.css | 30 ++++++++-- 4 files changed, 140 insertions(+), 39 deletions(-) create mode 100644 components/refine-bio-ex-logo.svg diff --git a/02-microarray/00-intro-to-microarray.html b/02-microarray/00-intro-to-microarray.html index 782b8e98..1d53dcdc 100644 --- a/02-microarray/00-intro-to-microarray.html +++ b/02-microarray/00-intro-to-microarray.html @@ -2554,15 +2554,6 @@ }; - - @@ -2934,15 +2941,20 @@ diff --git a/components/_navbar.html b/components/_navbar.html index 15f2712f..1b902c8a 100644 --- a/components/_navbar.html +++ b/components/_navbar.html @@ -1,15 +1,20 @@ diff --git a/components/refine-bio-ex-logo.svg b/components/refine-bio-ex-logo.svg new file mode 100644 index 00000000..e001c3ee --- /dev/null +++ b/components/refine-bio-ex-logo.svg @@ -0,0 +1,57 @@ + + + + Logo + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/components/styles.css b/components/styles.css index 9a8f50c1..9ef20671 100644 --- a/components/styles.css +++ b/components/styles.css @@ -1,7 +1,7 @@ html, body { font-family: 'Lato', sans-serif; - font-size: 14px; + font-size: 16px; -webkit-font-smoothing: antialiased; line-height: 1.5; } @@ -33,19 +33,37 @@ a { color: #386db0; line-height: 1; } -.navbar-default { +.navbar-default, .navbar-nav, .navbar-inverse{ font-size: 1rem; + max-width: 100%; background-color: #386db0 !important; - color: #FDFDFD; + color: #FDFDFD !important; } -.navbar-brand, nav a { - color: #000000 !important; + +.navbar-nav>li>a { + font-size: 1rem; + background-color: #386db0 !important; + color: #FDFDFD !important; +} + +.navbar-default .navbar-brand{ + color: #FDFDFD; !important; + float: left; + max-width: 100%; + display: block; + overflow: visible; + padding-bottom: 32px; } + ul.dropdown-menu { background-color: #FDFDFD !important; color: #000000 !important; } +.dropdown-menu>li>a:hover, .dropdown-menu>li>a:active { + background-color: #386db0 !important; + color: #FDFDFD !important; +} .list-group-item.active, .list-group-item.active:focus, .list-group-item.active:hover { background-color: #386db0 !important; - color: #000000 !important; + color: #FDFDFD !important; } From c6158e84a0fcca167a6c71b05053fa3345e5ede6 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Thu, 22 Oct 2020 10:11:01 -0400 Subject: [PATCH 22/50] Resolve render-notebooks.R conflict --- scripts/render-notebooks.R | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/render-notebooks.R b/scripts/render-notebooks.R index 71ef4533..61adb6eb 100644 --- a/scripts/render-notebooks.R +++ b/scripts/render-notebooks.R @@ -115,7 +115,6 @@ rmarkdown::render(tmp_file, output_format = rmarkdown::html_document( toc = TRUE, toc_depth = 2, toc_float = TRUE, number_sections = TRUE, - df_print = "paged", highlight = "haddock", df_print = "paged", css = normalizePath(file.path("components", "styles.css")) From 145fd989c9c7dcceb9ef14c374ad074107e82db5 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Thu, 22 Oct 2020 10:18:08 -0400 Subject: [PATCH 23/50] Remove testing html from file diff --- 02-microarray/00-intro-to-microarray.html | 94 ++--------------------- 1 file changed, 8 insertions(+), 86 deletions(-) diff --git a/02-microarray/00-intro-to-microarray.html b/02-microarray/00-intro-to-microarray.html index 1d53dcdc..45b74393 100644 --- a/02-microarray/00-intro-to-microarray.html +++ b/02-microarray/00-intro-to-microarray.html @@ -2608,73 +2608,6 @@ } - @@ -2941,20 +2874,15 @@ From 43b9ea75c0d8e95d60db621c77b9c94f65f3aaef Mon Sep 17 00:00:00 2001 From: dvenprasad Date: Thu, 22 Oct 2020 10:40:55 -0400 Subject: [PATCH 24/50] uncommented mobile nav --- 02-microarray/00-intro-to-microarray.html | 162 +++++++++++++++------- components/_navbar.html | 4 +- 2 files changed, 113 insertions(+), 53 deletions(-) diff --git a/02-microarray/00-intro-to-microarray.html b/02-microarray/00-intro-to-microarray.html index 45b74393..4694e5c0 100644 --- a/02-microarray/00-intro-to-microarray.html +++ b/02-microarray/00-intro-to-microarray.html @@ -1263,25 +1263,22 @@ }; - - + - - - @@ -2608,6 +2590,73 @@ } + @@ -2874,15 +2923,20 @@ @@ -3023,34 +3083,34 @@

0.4.1 Why doesn’t the gene I ca

References

-

Dai M., P. Wang, A. D. Boyd, G. Kostov, and B. Athey et al., 2005 Evolving gene/transcript definitions significantly alter the interpretation of GeneChip data. Nucleic Acids Res 33: e175.

+

Dai M., P. Wang, A. D. Boyd, G. Kostov, and B. Athey et al., 2005 Evolving gene/transcript definitions significantly alter the interpretation of GeneChip data. Nucleic Acids Research 33: e175. https://doi.org/10.1093/nar/gni179

-

Farina D., 2020 Gene expression analysis and DNA microarray assays

+

Farina D., 2020 Gene expression analysis and DNA microarray assays. https://www.youtube.com/watch?v=Hv5flUOsE0s

-

Govindarajan R., J. Duraiyan, K. Kaliyappan, and M. Palanisamy, 2012 Microarray and its applications. J Pharm Bioallied Sci 4: S310–312.

+

Govindarajan R., J. Duraiyan, K. Kaliyappan, and M. Palanisamy, 2012 Microarray and its applications. Journal of Pharmacy and Bioallied Sciences 4: S310–312. https://doi.org/10.4103/0975-7406.100283

-

LCSciences, 2014 Microarray or RNA sequencing?

+

LCSciences, 2014 Microarray or RNA sequencing? https://www.lcsciences.com/news/microarray-or-rna-sequencing/

-

Mantione K. J., R. M. Kream, H. Kuzelova, R. Ptacek, and J. Raboch et al., 2014 Comparing bioinformatic gene expression profiling methods: microarray and RNA-Seq. Med Sci Monit Basic Res 20: 138–142.

+

Mantione K. J., R. M. Kream, H. Kuzelova, R. Ptacek, and J. Raboch et al., 2014 Comparing bioinformatic gene expression profiling methods: Microarray and RNA-Seq. Medical Science Monitor Basic Research 20: 138–142. https://doi.org/10.12659/MSMBR.892101

-

Piccolo S. R., Y. Sun, J. D. Campbell, M. E. Lenburg, and A. H. Bild et al., 2012 A single-sample microarray normalization method to facilitate personalized-medicine workflows. Genomics 100: 337–344.

+

Piccolo S. R., Y. Sun, J. D. Campbell, M. E. Lenburg, and A. H. Bild et al., 2012 A single-sample microarray normalization method to facilitate personalized-medicine workflows. Genomics 100: 337–344. https://doi.org/10.1016/j.ygeno.2012.08.003

-

Sánchez A., and M. C. R. de Villa, 2008 A tutorial review of microarray data analysis

+

Sánchez A., and M. C. R. de Villa, 2008 A tutorial review of microarray data analysis. http://www.ub.edu/stat/docencia/bioinformatica/microarrays/ADM/slides/A_Tutorial_Review_of_Microarray_data_Analysis_17-06-08.pdf

-

Slonim D. K., and I. Yanai, 2009 Getting started in gene expression microarray analysis. PLoS Comput. Biol. 5: e1000543.

+

Slonim D. K., and I. Yanai, 2009 Getting started in gene expression microarray analysis. PLOS Computational Biology 5: e1000543. https://doi.org/10.1371/journal.pcbi.1000543

-

Tarca A. L., R. Romero, and S. Draghici, 2006 Analysis of microarray experiments of gene expression profiling. Am. J. Obstet. Gynecol. 195: 373–388.

+

Tarca A. L., R. Romero, and S. Draghici, 2006 Analysis of microarray experiments of gene expression profiling. American Journal of Obstetrics and Gynecology 195: 373–388. https://doi.org/10.1016/j.ajog.2006.07.001

-

Wu H., Introduction to gene expression microarray data analysis

+

Wu H., Introduction to gene expression microarray data analysis. http://web1.sph.emory.edu/users/hwu30/teaching/bioc/GE1.pdf

diff --git a/components/_navbar.html b/components/_navbar.html index 1b902c8a..1ed6c957 100644 --- a/components/_navbar.html +++ b/components/_navbar.html @@ -3,11 +3,11 @@
@@ -3033,31 +3848,31 @@

4.1 Install libraries

See our Getting Started page with instructions for package installation for a list of the other software you will need, as well as more tips and resources.

In this analysis, we will be using clusterProfiler package to perform ORA and the msigdbr package which contains gene sets from the Molecular Signatures Database (MSigDB) already in the tidy format required by clusterProfiler (Dolgalev 2020; Subramanian et al. 2005).

We will also need the org.Dr.eg.db package to perform gene identifier conversion and ggupset to make an UpSet plot (Carlson 2019; Ahlmann-Eltze 2020).

-
if (!("clusterProfiler" %in% installed.packages())) {
-  # Install this package if it isn't installed yet
-  BiocManager::install("clusterProfiler", update = FALSE)
-}
-
-# This is required to make one of the plots that clusterProfiler will make
-if (!("ggupset" %in% installed.packages())) {
-  # Install this package if it isn't installed yet
-  BiocManager::install("ggupset", update = FALSE)
-}
-
-if (!("msigdbr" %in% installed.packages())) {
-  # Install this package if it isn't installed yet
-  BiocManager::install("msigdbr", update = FALSE)
-}
-
-if (!("org.Dr.eg.db" %in% installed.packages())) {
-  # Install this package if it isn't installed yet
-  BiocManager::install("org.Dr.eg.db", update = FALSE)
-}
+
if (!("clusterProfiler" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("clusterProfiler", update = FALSE)
+}
+
+# This is required to make one of the plots that clusterProfiler will make
+if (!("ggupset" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("ggupset", update = FALSE)
+}
+
+if (!("msigdbr" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("msigdbr", update = FALSE)
+}
+
+if (!("org.Dr.eg.db" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("org.Dr.eg.db", update = FALSE)
+}

Attach the packages we need for this analysis.

-
# Attach the library
-library(clusterProfiler)
+
# Attach the library
+library(clusterProfiler)
## 
-
## clusterProfiler v3.16.1  For help: https://guangchuangyu.github.io/software/clusterProfiler
+
## clusterProfiler v3.18.0  For help: https://guangchuangyu.github.io/software/clusterProfiler
 ## 
 ## If you use clusterProfiler in published research, please cite:
 ## Guangchuang Yu, Li-Gen Wang, Yanyan Han, Qing-Yu He. clusterProfiler: an R package for comparing biological themes among gene clusters. OMICS: A Journal of Integrative Biology. 2012, 16(5):284-287.
@@ -3066,11 +3881,11 @@

4.1 Install libraries

## The following object is masked from 'package:stats':
 ## 
 ##     filter
-
# Package that contains MSigDB gene sets in tidy format
-library(msigdbr)
-
-# Danio rerio annotation package we'll use for gene identifier conversion
-library(org.Dr.eg.db)
+
# Package that contains MSigDB gene sets in tidy format
+library(msigdbr)
+
+# Danio rerio annotation package we'll use for gene identifier conversion
+library(org.Dr.eg.db)
## Loading required package: AnnotationDbi
## Loading required package: stats4
## Loading required package: BiocGenerics
@@ -3092,7 +3907,7 @@

4.1 Install libraries

## grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget, ## order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank, ## rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply, -## union, unique, unsplit, which, which.max, which.min
+## union, unique, unsplit, which.max, which.min
## Loading required package: Biobase
## Welcome to Bioconductor
 ## 
@@ -3120,21 +3935,22 @@ 

4.1 Install libraries

## ## select
## 
-
# We will need this so we can use the pipe: %>%
-library(magrittr)
+
# We will need this so we can use the pipe: %>%
+library(magrittr)

4.2 Import data

We will read in the differential expression results we will download from online. These results are from a zebrafish microarray experiment we used for differential expression analysis for two groups using limma (Ritchie et al. 2015). The table contains Ensembl gene IDs, log fold-changes for each group, and adjusted p-values (FDR in this case). We can identify differentially regulated genes by filtering these results and use this list as input to ORA.

Instead of using the URL below, you can use a file path to a TSV file with your desired gene list results. First we will assign the URL to its own variable called, dge_url.

-
# Define the url to your differential expression results file
-dge_url <- "https://refinebio-examples.s3.us-east-2.amazonaws.com/02-microarray/results/GSE71270/GSE71270_limma_results.tsv"
+
# Define the url to your differential expression results file
+dge_url <- "https://refinebio-examples.s3.us-east-2.amazonaws.com/02-microarray/results/GSE71270/GSE71270_limma_results.tsv"

Read in the file that has differential expression results. Here we are using the URL we set up above, but this can be a local file path instead i.e. you can replace dge_url in the code below with a path to file you have on your computer like: file.path("results", "GSE71270_limma_results.tsv").

-
# Read in the contents of your differential expression results file
-# `dge_url` can be replaced with a file path to a TSV file with your
-# desired gene list results
-dge_df <- readr::read_tsv(dge_url)
-
## Parsed with column specification:
+
# Read in the contents of your differential expression results file
+# `dge_url` can be replaced with a file path to a TSV file with your
+# desired gene list results
+dge_df <- readr::read_tsv(dge_url)
+
## 
+## ── Column specification ────────────────────────────────────────────────────────────────
 ## cols(
 ##   Gene = col_character(),
 ##   logFC = col_double(),
@@ -3145,7 +3961,7 @@ 

4.2 Import data

## B = col_double() ## )

read_tsv() can read TSV files online and doesn’t necessarily require you download the file first. Let’s take a look at what these contrast results from the differential expression analysis look like.

-
dge_df
+
dge_df

The data we’re interested in here comes from zebrafish samples, so we can obtain just the gene sets relevant to D. rerio with the species argument to msigdbr().

-
dr_msigdb_df <- msigdbr(species = "Danio rerio")
+
dr_msigdb_df <- msigdbr(species = "Danio rerio")

MSigDB contains 8 different gene set collections (Subramanian et al. 2005).

H: hallmark gene sets
 C1: positional gene sets
@@ -3175,20 +3991,20 @@ 

4.3 Getting familiar with c

In this example, we will use pathways that are gene sets considered to be “canonical representations of a biological process compiled by domain experts” and are a subset of C2: curated gene sets (Subramanian et al. 2005).

Specifically, we will use the KEGG (Kyoto Encyclopedia of Genes and Genomes) pathways (Kanehisa and Goto 2000).

First, let’s take a look at what information is included in this data frame.

-
head(dr_msigdb_df)
+
head(dr_msigdb_df)

We will need to use gs_cat and gs_subcat columns to construct a filter step that will only keep curated gene sets and KEGG pathways.

-
# Filter the zebrafish data frame to the KEGG pathways that are included in the
-# curated gene sets
-dr_kegg_df <- dr_msigdb_df %>%
-  dplyr::filter(
-    gs_cat == "C2", # This is to filter only to the C2 curated gene sets
-    gs_subcat == "CP:KEGG" # This is because we only want KEGG pathways
-  )
+
# Filter the zebrafish data frame to the KEGG pathways that are included in the
+# curated gene sets
+dr_kegg_df <- dr_msigdb_df %>%
+  dplyr::filter(
+    gs_cat == "C2", # This is to filter only to the C2 curated gene sets
+    gs_subcat == "CP:KEGG" # This is because we only want KEGG pathways
+  )

Note: We could have specified that we wanted the KEGG gene sets using the category and subcategory arguments of msigdbr(), but we’re going for general steps! – use ?msigdbr to see more information.

The clusterProfiler() function we will use requires a data frame with two columns, where one column contains the term identifier or name and one column contains gene identifiers that match our gene lists we want to check for enrichment.

Our data frame with KEGG terms contains Entrez IDs and gene symbols.

@@ -3200,7 +4016,7 @@

4.4 Gene identifier conversionThe annotation package org.Dr.eg.db contains information for different identifiers (Carlson 2019). org.Dr.eg.db is specific to Danio rerio – this is what the Dr in the package name is referencing.

Take a look at our other gene identifier conversion examples for examples with different species and gene ID types: the microarray example and the RNA-seq example.

We can see what types of IDs are available to us in an annotation package with keytypes().

-
keytypes(org.Dr.eg.db)
+
keytypes(org.Dr.eg.db)
##  [1] "ACCNUM"       "ALIAS"        "ENSEMBL"      "ENSEMBLPROT"  "ENSEMBLTRANS"
 ##  [6] "ENTREZID"     "ENZYME"       "EVIDENCE"     "EVIDENCEALL"  "GENENAME"    
 ## [11] "GO"           "GOALL"        "IPI"          "ONTOLOGY"     "ONTOLOGYALL" 
@@ -3208,50 +4024,50 @@ 

4.4 Gene identifier conversion

Even though we’ll use this package to convert from Ensembl gene IDs (ENSEMBL) to gene symbols (SYMBOL), we could just as easily use it to convert from an Ensembl transcript ID (ENSEMBLTRANS) to Entrez IDs (ENTREZID).

The function we will use to map from Ensembl gene IDs to gene symbols is called mapIds().

-
# This returns a named vector which we can convert to a data frame, where
-# the keys (Ensembl IDs) are the names
-symbols_vector <- mapIds(org.Dr.eg.db, # Specify the annotation package
-  # The vector of gene identifiers we want to map
-  keys = dge_df$Gene,
-  # The type of gene identifier we want returned
-  column = "SYMBOL",
-  # What type of gene identifiers we're starting with
-  keytype = "ENSEMBL",
-  # In the case of 1:many mappings, return the
-  # first one. This is default behavior!
-  multiVals = "first"
-)
+
# This returns a named vector which we can convert to a data frame, where
+# the keys (Ensembl IDs) are the names
+symbols_vector <- mapIds(org.Dr.eg.db, # Specify the annotation package
+  # The vector of gene identifiers we want to map
+  keys = dge_df$Gene,
+  # The type of gene identifier we want returned
+  column = "SYMBOL",
+  # What type of gene identifiers we're starting with
+  keytype = "ENSEMBL",
+  # In the case of 1:many mappings, return the
+  # first one. This is default behavior!
+  multiVals = "first"
+)
## 'select()' returned 1:many mapping between keys and columns

This message is letting us know that sometimes Ensembl gene identifiers will map to multiple gene symbols. In this case, it’s also possible that a gene symbol will map to multiple Ensembl IDs. For more about how to explore this, take a look at our microarray gene ID conversion example.

Let’s create a two column data frame that shows the gene symbols and their Ensembl IDs side-by-side.

-
# We would like a data frame we can join to the differential expression stats
-gene_key_df <- data.frame(
-  ensembl_id = names(symbols_vector),
-  gene_symbol = symbols_vector,
-  stringsAsFactors = FALSE
-) %>%
-  # If an Ensembl gene identifier doesn't map to a gene symbol, drop that
-  # from the data frame
-  dplyr::filter(!is.na(gene_symbol))
+
# We would like a data frame we can join to the differential expression stats
+gene_key_df <- data.frame(
+  ensembl_id = names(symbols_vector),
+  gene_symbol = symbols_vector,
+  stringsAsFactors = FALSE
+) %>%
+  # If an Ensembl gene identifier doesn't map to a gene symbol, drop that
+  # from the data frame
+  dplyr::filter(!is.na(gene_symbol))

Let’s see a preview of gene_key_df.

-
head(gene_key_df)
+
head(gene_key_df)

Now we are ready to add the gene_key_df to our data frame with the differential expression stats, dge_df. Here we’re using a dplyr::left_join() because we only want to retain the genes that have gene symbols and this will filter out anything in our dge_df that does not have gene symbols when we join using the Ensembl gene identifiers.

-
dge_annot_df <- gene_key_df %>%
-  # Using a left join removes the rows without gene symbols because those rows
-  # have already been removed in `gene_symbols_df`
-  dplyr::left_join(dge_df,
-    # The name of the column that contains the Ensembl gene IDs
-    # in the left data frame and right data frame
-    by = c("ensembl_id" = "Gene")
-  )
+
dge_annot_df <- gene_key_df %>%
+  # Using a left join removes the rows without gene symbols because those rows
+  # have already been removed in `gene_symbols_df`
+  dplyr::left_join(dge_df,
+    # The name of the column that contains the Ensembl gene IDs
+    # in the left data frame and right data frame
+    by = c("ensembl_id" = "Gene")
+  )

Let’s take a look at what this data frame looks like.

-
# Print out a preview
-head(dge_annot_df)
+
# Print out a preview
+head(dge_annot_df)

Looks like there are four KEGG sets returned as significant at FDR of 0.1.

@@ -3328,52 +4144,52 @@

4.8 Run ORA using the enric

4.9 Visualizing results

We can use a dot plot to visualize our significant enrichment results. The enrichplot::dotplot() function will only plot gene sets that are significant according to the multiple testing corrected p values (in the p.adjust column) and the pvalueCutoff you provided in the enricher() step.

-
enrich_plot <- enrichplot::dotplot(kegg_ora_results)
-
-# Print out the plot here
-enrich_plot
-

+
enrich_plot <- enrichplot::dotplot(kegg_ora_results)
+
+# Print out the plot here
+enrich_plot
+

Use ?enrichplot::dotplot to see the help page for more about how to use this function.

This plot is arguably more useful when we have a large number of significant pathways.

Let’s save it to a PNG.

-
ggplot2::ggsave(file.path(plots_dir, "GSE71270_ora_enrich_plot.png"),
-  plot = enrich_plot
-)
+
ggplot2::ggsave(file.path(plots_dir, "GSE71270_ora_enrich_plot.png"),
+  plot = enrich_plot
+)
## Saving 7 x 5 in image

We can use an UpSet plot to visualize the overlap between the gene sets that were returned as significant.

-
enrichplot::upsetplot(kegg_ora_results)
+
enrichplot::upsetplot(kegg_ora_results)

See that KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION and KEGG_LYSOSOME have all their genes in common. Gene sets or pathways aren’t independent!

Let’s also save this to a PNG.

-
ggplot2::ggsave(file.path(plots_dir, "GSE71270_ora_upset_plot.png"),
-  plot = enrich_plot
-)
+
ggplot2::ggsave(file.path(plots_dir, "GSE71270_ora_upset_plot.png"),
+  plot = enrich_plot
+)
## Saving 7 x 5 in image

4.10 Write results to file

-
readr::write_tsv(
-  kegg_result_df,
-  file.path(
-    results_dir,
-    "GSE71270_pathway_analysis_results.tsv"
-  )
-)
+
readr::write_tsv(
+  kegg_result_df,
+  file.path(
+    results_dir,
+    "GSE71270_pathway_analysis_results.tsv"
+  )
+)

5 Resources for further learning

6 Session info

At the end of every analysis, before saving your notebook, we recommend printing out your session info. This helps make your code more reproducible by recording what versions of software and packages you used to run this.

-
# Print session info
-sessionInfo()
+
# Print session info
+sessionInfo()
## R version 4.0.2 (2020-06-22)
 ## Platform: x86_64-pc-linux-gnu (64-bit)
 ## Running under: Ubuntu 20.04 LTS
@@ -3394,86 +4210,88 @@ 

6 Session info

## [8] methods base ## ## other attached packages: -## [1] magrittr_1.5 org.Dr.eg.db_3.11.4 AnnotationDbi_1.50.3 -## [4] IRanges_2.22.2 S4Vectors_0.26.1 Biobase_2.48.0 -## [7] BiocGenerics_0.34.0 msigdbr_7.2.1 clusterProfiler_3.16.1 +## [1] magrittr_1.5 org.Dr.eg.db_3.12.0 AnnotationDbi_1.52.0 +## [4] IRanges_2.24.0 S4Vectors_0.28.0 Biobase_2.50.0 +## [7] BiocGenerics_0.36.0 msigdbr_7.2.1 clusterProfiler_3.18.0 ## [10] optparse_1.6.6 ## ## loaded via a namespace (and not attached): -## [1] enrichplot_1.8.1 bit64_4.0.5 progress_1.2.2 -## [4] httr_1.4.2 RColorBrewer_1.1-2 R.cache_0.14.0 -## [7] tools_4.0.2 backports_1.1.10 R6_2.4.1 -## [10] DBI_1.1.0 colorspace_1.4-1 prettyunits_1.1.1 -## [13] tidyselect_1.1.0 gridExtra_2.3 curl_4.3 -## [16] bit_4.0.4 compiler_4.0.2 cli_2.0.2 -## [19] scatterpie_0.1.5 xml2_1.3.2 labeling_0.3 -## [22] triebeard_0.3.0 scales_1.1.1 readr_1.3.1 -## [25] ggridges_0.5.2 stringr_1.4.0 digest_0.6.25 -## [28] ggupset_0.3.0 rmarkdown_2.4 DOSE_3.14.0 -## [31] R.utils_2.10.1 pkgconfig_2.0.3 htmltools_0.5.0 -## [34] styler_1.3.2 rlang_0.4.7 rstudioapi_0.11 -## [37] RSQLite_2.2.0 gridGraphics_0.5-0 generics_0.0.2 -## [40] farver_2.0.3 jsonlite_1.7.1 BiocParallel_1.22.0 -## [43] GOSemSim_2.14.2 dplyr_1.0.2 R.oo_1.24.0 -## [46] ggplotify_0.0.5 GO.db_3.11.4 Matrix_1.2-18 -## [49] Rcpp_1.0.5 munsell_0.5.0 fansi_0.4.1 -## [52] viridis_0.5.1 lifecycle_0.2.0 R.methodsS3_1.8.1 -## [55] stringi_1.5.3 yaml_2.2.1 ggraph_2.0.3 -## [58] MASS_7.3-51.6 plyr_1.8.6 qvalue_2.20.0 -## [61] grid_4.0.2 blob_1.2.1 ggrepel_0.8.2 -## [64] DO.db_2.9 crayon_1.3.4 lattice_0.20-41 -## [67] cowplot_1.1.0 graphlayouts_0.7.0 splines_4.0.2 -## [70] hms_0.5.3 knitr_1.30 pillar_1.4.6 -## [73] fgsea_1.14.0 igraph_1.2.5 reshape2_1.4.4 -## [76] fastmatch_1.1-0 glue_1.4.2 evaluate_0.14 -## [79] downloader_0.4 BiocManager_1.30.10 data.table_1.13.0 -## [82] urltools_1.7.3 vctrs_0.3.4 tweenr_1.0.1 -## [85] gtable_0.3.0 getopt_1.20.3 purrr_0.3.4 -## [88] polyclip_1.10-0 tidyr_1.1.2 rematch2_2.1.2 -## [91] assertthat_0.2.1 ggplot2_3.3.2 xfun_0.18 -## [94] ggforce_0.3.2 europepmc_0.4 tidygraph_1.2.0 -## [97] viridisLite_0.3.0 tibble_3.0.3 rvcheck_0.1.8 -## [100] memoise_1.1.0 ellipsis_0.3.1
+## [1] enrichplot_1.10.0 bit64_4.0.5 RColorBrewer_1.1-2 +## [4] R.cache_0.14.0 tools_4.0.2 backports_1.1.10 +## [7] R6_2.4.1 DBI_1.1.0 colorspace_1.4-1 +## [10] tidyselect_1.1.0 gridExtra_2.3 curl_4.3 +## [13] bit_4.0.4 compiler_4.0.2 cli_2.1.0 +## [16] scatterpie_0.1.5 labeling_0.3 shadowtext_0.0.7 +## [19] scales_1.1.1 readr_1.4.0 stringr_1.4.0 +## [22] digest_0.6.25 ggupset_0.3.0 rmarkdown_2.4 +## [25] DOSE_3.16.0 R.utils_2.10.1 pkgconfig_2.0.3 +## [28] htmltools_0.5.0 styler_1.3.2 rlang_0.4.8 +## [31] rstudioapi_0.11 RSQLite_2.2.1 generics_0.0.2 +## [34] farver_2.0.3 jsonlite_1.7.1 BiocParallel_1.24.1 +## [37] GOSemSim_2.16.1 dplyr_1.0.2 R.oo_1.24.0 +## [40] GO.db_3.12.1 Matrix_1.2-18 Rcpp_1.0.5 +## [43] munsell_0.5.0 fansi_0.4.1 viridis_0.5.1 +## [46] lifecycle_0.2.0 R.methodsS3_1.8.1 stringi_1.5.3 +## [49] yaml_2.2.1 ggraph_2.0.3 MASS_7.3-51.6 +## [52] plyr_1.8.6 qvalue_2.22.0 grid_4.0.2 +## [55] blob_1.2.1 ggrepel_0.8.2 DO.db_2.9 +## [58] crayon_1.3.4 lattice_0.20-41 cowplot_1.1.0 +## [61] graphlayouts_0.7.0 splines_4.0.2 hms_0.5.3 +## [64] ps_1.4.0 knitr_1.30 pillar_1.4.6 +## [67] fgsea_1.16.0 igraph_1.2.6 reshape2_1.4.4 +## [70] fastmatch_1.1-0 glue_1.4.2 evaluate_0.14 +## [73] downloader_0.4 BiocManager_1.30.10 data.table_1.13.0 +## [76] vctrs_0.3.4 tweenr_1.0.1 gtable_0.3.0 +## [79] getopt_1.20.3 purrr_0.3.4 polyclip_1.10-0 +## [82] tidyr_1.1.2 rematch2_2.1.2 assertthat_0.2.1 +## [85] ggplot2_3.3.2 xfun_0.18 ggforce_0.3.2 +## [88] tidygraph_1.2.0 viridisLite_0.3.0 tibble_3.0.4 +## [91] rvcheck_0.1.8 memoise_1.1.0 ellipsis_0.3.1

References

-

Ahlmann-Eltze C., 2020 Ggupset: Combination matrix axis for ’ggplot2’ to create ’upset’ plots.

+

Ahlmann-Eltze C., 2020 ggupset: Combination matrix axis for ’ggplot2’ to create ’upset’ plots. https://github.com/const-ae/ggupset

-

Carlson M., 2019 Genome wide annotation for zebrafish

+

Carlson M., 2019 Genome wide annotation for zebrafish. https://bioconductor.org/packages/release/data/annotation/html/org.Dr.eg.db.html

-

Dolgalev I., 2020 Msigdbr: MSigDB gene sets for multiple organisms in a tidy data format.

-
-
-

Guangchuang Yu, ClusterProfiler: Universal enrichment tool for functional and comparative study

+

Dolgalev I., 2020 Msigdbr: MSigDB gene sets for multiple organisms in a tidy data format. https://cran.r-project.org/web/packages/msigdbr/index.html

-

Kanehisa M., and S. Goto, 2000 KEGG: kyoto encyclopedia of genes and genomes. Nucleic Acids Res 28: 27–30.

+

Kanehisa M., and S. Goto, 2000 KEGG: Kyoto encyclopedia of genes and genomes. Nucleic Acids Research 28: 27–30. https://doi.org/10.1093/nar/28.1.27

-

Khatri P., M. Sirota, and A. J. Butte, 2012 Ten years of pathway analysis: current approaches and outstanding challenges. PLoS Comput. Biol. 8: e1002375.

+

Khatri P., M. Sirota, and A. J. Butte, 2012 Ten years of pathway analysis: Current approaches and outstanding challenges. PLOS Computational Biology 8: e1002375. https://doi.org/10.1371/journal.pcbi.1002375

Ritchie M. E., B. Phipson, D. Wu, Y. Hu, and C. W. Law et al., 2015 limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Research 43: e47. https://doi.org/10.1093/nar/gkv007

-

Subramanian A., P. Tamayo, V. K. Mootha, S. Mukherjee, and B. L. Ebert et al., 2005 Gene set enrichment analysis: a knowledge-based approach for interpreting genome-wide expression profiles. Proc Natl Acad Sci U S A 102: 15545–15550.

+

Subramanian A., P. Tamayo, V. K. Mootha, S. Mukherjee, and B. L. Ebert et al., 2005 Gene set enrichment analysis: A knowledge-based approach for interpreting genome-wide expression profiles. Proceedings of the National Academy of Sciences 102: 15545–15550. https://doi.org/10.1073/pnas.0506580102

-

Tregnago C., E. Manara, M. Zampini, V. Bisio, and C. Borga et al., 2016 CREB engages C/EBPδ to initiate leukemogenesis. Leukemia 30: 1887–1896.

+

Tregnago C., E. Manara, M. Zampini, V. Bisio, and C. Borga et al., 2016 CREB engages C/EBPδ to initiate leukemogenesis. Leukemia 30: 1887–1896. https://doi.org/10.1038/leu.2016.98

-

Yaari G., C. R. Bolen, J. Thakar, and S. H. Kleinstein, 2013 Quantitative set analysis for gene expression: a method to quantify gene set differential expression including gene-gene correlations. Nucleic Acids Res. 41: e170.

+

Yaari G., C. R. Bolen, J. Thakar, and S. H. Kleinstein, 2013 Quantitative set analysis for gene expression: A method to quantify gene set differential expression including gene-gene correlations. Nucleic Acids Research 41: e170. https://doi.org/10.1093/nar/gkt660

-

Yu G., L.-G. Wang, Y. Han, and Q.-Y. He, 2012 ClusterProfiler: An r package for comparing biological themes among gene clusters. OMICS: A Journal of Integrative Biology 16: 284–287. https://doi.org/10.1089/omi.2011.0118

+

Yu G., L.-G. Wang, Y. Han, and Q.-Y. He, 2012 clusterProfiler: An R package for comparing biological themes among gene clusters. OMICS: A Journal of Integrative Biology 16: 284–287. https://doi.org/10.1089/omi.2011.0118

+
+
+

Yu G., clusterProfiler: Universal enrichment tool for functional and comparative study. http://yulab-smu.top/clusterProfiler-book/index.html

+
diff --git a/02-microarray/pathway-analysis_microarray_01_ortholog_mapping_kegg.Rmd b/02-microarray/pathway-analysis_microarray_01_ortholog_mapping_kegg.Rmd deleted file mode 100644 index aba23317..00000000 --- a/02-microarray/pathway-analysis_microarray_01_ortholog_mapping_kegg.Rmd +++ /dev/null @@ -1,272 +0,0 @@ ---- -title: "KEGG pathways: mapping to mouse orthologs with `hcop`" -output: - html_notebook: - toc: TRUE - toc_float: TRUE -author: J. Taroni for ALSF CCDL -date: 2019 ---- - -## Background - -In this module, we use QuSAGE ([](https://doi.org/10.1093/nar/gkt660)) -for pathway analysis (implemented in the [`qusage` bioconductor package](https://bioconductor.org/packages/release/bioc/html/qusage.html)). - -`qusage` allows you to read in gene sets that are in the [GMT format](http://software.broadinstitute.org/cancer/software/gsea/wiki/index.php/Data_formats#GMT:_Gene_Matrix_Transposed_file_format_.28.2A.gmt.29). - -[MSigDB](http://software.broadinstitute.org/gsea/msigdb) offers gene sets in this format. -[Curated gene sets](http://software.broadinstitute.org/gsea/msigdb/collections.jsp#C2) -such as [KEGG](https://www.genome.jp/kegg/) are a good starting point for any pathway analysis. - -However, MSigDB only distributes human pathways. -If we want to use KEGG Pathways with another species without going through -[KEGG Orthology](https://www.genome.jp/kegg/ko.html), we need to map to -orthologs ourselves. - -We'll use the [`hcop` package](https://github.com/stephenturner/hcop) to do -this. -If you're looking for a little bit more background information (like if you -run into trouble installing `hcop`), check out the notebook in our -[`ortholog-mapping`](https://github.com/AlexsLemonade/refinebio-examples/tree/master/ortholog-mapping) module. - -## Setup - -Package installation - -```{r} -# need read.gmt functionality from qusage -if (!("qusage" %in% installed.packages())) { - BiocManager::install("qusage", update = FALSE) -} - -# we need devtools in order to install the hcop package we will use to -# do the ortholog mapping -if (!("devtools" %in% installed.packages())) { - install.packages("devtools") -} - -# this installs a specific version of hcop -# we pass the commit hash to the ref argument -devtools::install_github("stephenturner/hcop", - ref = "0985fddc91a6ef2308f4800958dfd11c25fe6a98" -) -``` - -```{r} -`%>%` <- dplyr::`%>%` -``` - -```{r} -library(hcop) -``` - -## KEGG human pathways - -We need to download the the MSigDB v6.2 KEGG gene sets that use Entrez gene IDs -and place them at the following path if we have not done so already: - -``` -gene-sets/c2.cp.kegg.v6.2.entrez.gmt -``` - -```{r} -# the kegg gmt file should be located in the spot we mention above -kegg_file <- file.path("gene-sets", "c2.cp.kegg.v6.2.entrez.gmt") -# since we do not track this file in our repository, let's check to make sure -# it exists where we expect it and download it if we don't find it -if (!file.exists(kegg_file)) { - message(paste( - "KEGG GMT file is not found at", kegg_file, - ", downloading now..." - )) - # need gene-sets directory - if (!dir.exists("gene-sets")) { - dir.create("gene-sets") - } - download.file("https://data.broadinstitute.org/gsea-msigdb/msigdb/release/6.2/c2.cp.kegg.v6.2.entrez.gmt", - destfile = kegg_file - ) -} -``` - -Read in the pathway file - -```{r} -kegg_human_list <- qusage::read.gmt(kegg_file) -``` - -## Conversion from human Entrez ID to mouse symbol - -### Human to mouse mapping with `hcop` - -`hcop` is designed to work well with `dplyr`, so we'll get all the possible -human Entrez IDs into a `data.frame`. - -```{r} -entrez_in_pathways_df <- data.frame( - human_entrez = as.integer(unique(unlist(kegg_human_list))) -) -``` - -Join to mouse orthologs by the human Entrez IDs. - -```{r} -# Join to mouse orthologs -mouse_ortholog_df <- entrez_in_pathways_df %>% - dplyr::inner_join(mouse, by = "human_entrez") -``` - -### 1:many mapping - -For 1:many mappings, we'll pick the one with the most support. -Here, we'll only consider the _number_ of sources without any regard for _what_ -those resources are. -Essentially, we weigh all sources equally though they likely have more or less -permissive criteria. - -```{r} -# add a column that counts resources -mouse_ortholog_df <- mouse_ortholog_df %>% - dplyr::rowwise() %>% - dplyr::mutate( - num_resources_support = - length(stringr::str_split(support, - pattern = ",", - simplify = TRUE - )) - ) -``` - -To demonstrate how this works, we'll pick a gene that had 1:many mappings -and follow it along. - -```{r} -mouse_ortholog_df %>% - dplyr::filter(human_entrez == 5631) %>% - dplyr::select( - human_entrez, mouse_entrez, human_symbol, mouse_symbol, - num_resources_support - ) -``` - -We can see that the human gene _PRPS1_/`5631` maps to 4 mouse genes, one of -which has 10 resources supporting that mapping. - -```{r} -# for each unique human entrez id, pick the mapping with the highest number of -# resources supporting it -most_support_df <- mouse_ortholog_df %>% - dplyr::group_by(human_entrez) %>% - dplyr::top_n(1, num_resources_support) -``` - -What happened to `5631`? - -```{r} -most_support_df %>% - dplyr::filter(human_entrez == 5631) %>% - dplyr::select( - human_entrez, mouse_entrez, human_symbol, mouse_symbol, - num_resources_support - ) -``` - -We successfully selected the mapping with the highest number of resources -supporting it. - -### Conversion of KEGG pathways - -For each KEGG pathway we have (currently populated with human Entrez IDs), -we need a new gene set that is comprised of mouse gene symbols. - -```{r} -kegg_mouse_list <- - lapply( - kegg_human_list, - function(pathway) { - dplyr::filter(most_support_df, human_entrez %in% pathway) %>% - dplyr::pull(mouse_symbol) - } - ) -``` - -Do the results this seem reasonable? -Let's pick the polymerase pathway, where our success should be pretty obvious -from the mouse gene symbols. - -```{r} -kegg_mouse_list[[grep( - "POLYMERASE", # Replace with a word (case sensitive) or phrase that would filter in your desired pathway(s) - names(kegg_mouse_list) -)]] -``` - -### Write mouse pathway list in `GMT` format - -We need to write this new mouse pathway list to file in [GMT format](http://software.broadinstitute.org/cancer/software/gsea/wiki/index.php/Data_formats#GMT:_Gene_Matrix_Transposed_file_format_.28.2A.gmt.29), as this will facilitate use with downstream pathway analysis. - -Briefly, the GMT format has one pathway per line and it follows this pattern: - -``` -\t\t... -``` - -We've lost the description information because it's removed by -`qusage::read.gmt`. -The description in `r kegg_file` follows this pattern: - -``` -http://www.broadinstitute.org/gsea/msigdb/cards/ -``` - -We can pretty easily stick this back in when we write to file with `write()`. - -```{r} -# filename we're going to write to -mouse_file <- file.path( - "gene-sets", # Replace with path to desired output directory - "c2.cp.kegg.v6.2.entrez_mouse_symbol_hcop.gmt" # Replace with name for output file -) - -# if you run this again after making changes above, you'd just end up appending -# this to the end of your old file, so we should take steps to get rid of -# the existing file -if (file.exists(mouse_file)) { - message(paste("Removing old", mouse_file)) - file.remove(mouse_file) -} - -# for each pathway, write it to line following GMT format -for (pathway_iter in seq_along(kegg_mouse_list)) { - # extract the current pathway name - pathway_name <- names(kegg_mouse_list)[pathway_iter] - text_to_write <- - paste( - # the name of the pathway - pathway_name, - # the description -- this is stripped out by qusage::read.gmt - paste0( - "http://www.broadinstitute.org/gsea/msigdb/cards/", - pathway_name - ), - # the gene symbols - paste(kegg_mouse_list[[pathway_iter]], collapse = "\t"), - sep = "\t" - ) - write(text_to_write, mouse_file, append = TRUE) -} -``` - -We can double check how this went by reading it back in with `qusage::read.gmt`. - -```{r} -mouse_read_list <- qusage::read.gmt(mouse_file) -all.equal(mouse_read_list, kegg_mouse_list) -``` - -## Session Info - -```{r} -sessioninfo::session_info() -``` diff --git a/02-microarray/pathway-analysis_microarray_03_gsea.Rmd b/02-microarray/pathway-analysis_microarray_02_gsea.Rmd similarity index 99% rename from 02-microarray/pathway-analysis_microarray_03_gsea.Rmd rename to 02-microarray/pathway-analysis_microarray_02_gsea.Rmd index 0c414a56..051b639d 100644 --- a/02-microarray/pathway-analysis_microarray_03_gsea.Rmd +++ b/02-microarray/pathway-analysis_microarray_02_gsea.Rmd @@ -27,7 +27,7 @@ We recommend taking a look at our [Resources for Learning R](https://alexslemona ## Obtain the `.Rmd` file -To run this example yourself, [download the `.Rmd` for this analysis by clicking this link](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_03_gsea.Rmd). +To run this example yourself, [download the `.Rmd` for this analysis by clicking this link](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_02_gsea.Rmd). Clicking this link will most likely send this to your downloads folder on your computer. Move this `.Rmd` file to where you would like this example and its files to be stored. diff --git a/02-microarray/pathway-analysis_microarray_03_gsea.html b/02-microarray/pathway-analysis_microarray_02_gsea.html similarity index 100% rename from 02-microarray/pathway-analysis_microarray_03_gsea.html rename to 02-microarray/pathway-analysis_microarray_02_gsea.html diff --git a/02-microarray/pathway-analysis_microarray_03_qusage_meta_analysis.Rmd b/02-microarray/pathway-analysis_microarray_03_qusage_meta_analysis.Rmd deleted file mode 100644 index a3192ca9..00000000 --- a/02-microarray/pathway-analysis_microarray_03_qusage_meta_analysis.Rmd +++ /dev/null @@ -1,512 +0,0 @@ ---- -title: "Pathway analysis with QuSAGE: Meta-analysis of medulloblastoma" -output: - html_notebook: - toc: TRUE - toc_float: TRUE -author: J. Taroni for ALSF CCDL -date: 2019 ---- - -## Background - -The Quantitative Set Analysis of Gene Expression (QuSAGE) -([](https://doi.org/10.1093/nar/gkt660)) framework -has advantages that we outline in -[`qusage_single_dataset`](./qusage_single_dataset.nb.html), including the -fact that it returns more than just a p-value. -Specifically, QuSAGE quantifies gene set activity with a full probability -density function (PDF). -If we're interested in pathway analysis of multiple datasets, QuSAGE allows -us to perform a _meta-analysis_ by combining distributions from the QuSAGE -results from each dataset. -Meta-analysis with QuSAGE is described in -[ et al. _PLOS Comp Bio._ 2019.](https://doi.org/10.1371/journal.pcbi.1006899) -and implemented in the [`qusage` bioconductor package](https://bioconductor.org/packages/release/bioc/html/qusage.html). -The [`qusage` vignette](https://bioconductor.org/packages/release/bioc/vignettes/qusage/inst/doc/qusage.pdf) -contains a section on meta-analysis. - -## Datasets - -We will use two medulloblastoma datasets— -[Northcott et al.](https://doi.org/10.1038/nature11327) and -[Robinson et al.](https://doi.org/10.1038/nature11213)—to demonstrate how to -perform meta-analysis with `qusage`. -Specifically, we'll identify pathways that are differentially active between -the SHH subgroup vs. the Group 3 and 4 subgroups in both datasets. -These datasets are -[`GSE37382`](https://www.refine.bio/experiments/GSE37382/subgroup-specific-somatic-copy-number-aberrations-in-the-medulloblastoma-genome-mrna) and -[`GSE37418`](https://www.refine.bio/experiments/GSE37418/novel-mutations-target-distinct-subgroups-of-medulloblastoma), respectively. - -## Set up - -### Package installation and loading - -```{r} -if (!("qusage" %in% installed.packages())) { - BiocManager::install("qusage", update = FALSE) -} - -if (!("org.Hs.eg.db" %in% installed.packages())) { - BiocManager::install("org.Hs.eg.db", update = FALSE) -} -``` - -```{r} -`%>%` <- dplyr::`%>%` -``` - -```{r} -library(org.Hs.eg.db) -library(qusage) -``` - -### Directories - -Make directories to hold the plots and results if they do not yet exist. - -```{r} -# Define the file path to the plots directory -plots_dir <- "plots" # Replace with path to desired output plots directory - -# Make a plots directory if it isn't created yet -if (!dir.exists(plots_dir)) { - dir.create(plots_dir) -} - -# Define the file path to the results directory -results_dir <- "results" # Replace with path to desired output results directory - -# Make a results directory if it isn't created yet -if (!dir.exists(results_dir)) { - dir.create(results_dir) -} - -# Define the file path to the data directory -data_dir <- "data" -``` - -### Function - -Function to perform gene identifier conversion -- we'll do this once for -each dataset. -We 'functionalize' it to keep from repeating ourselves. -For an example where we do the conversion without using a custom function, see -[`qusage_single_dataset`](./qusage_single_dataset.nb.html) or -[`qusage_replicate_vignette`](./qusage_replicate_vignette.nb.html). - -```{r} -convert_ensembl_to_entrez_mat <- function(exprs_df) { - # Given a data.frame that contains human gene expression values and a column - # (named ENSEMBL) that contains Ensembl gene IDs, return an expression matrix - # where the rownames are Entrez IDs. In the case of duplicate Entrez - # identifiers, we summarize to the mean value for an Entrez ID. Mapping - # is performed with AnnotationDbi::mapIDs. - # - # Args: - # exprs_df: A data.frame of gene expression data. The first column should be - # named ENSEMBL and contain Ensembl gene IDs. Rows are genes; - # columns are samples. - # Returns: - # An expression matrix where the rownames are Entrez gene IDs - - `%>%` <- dplyr::`%>%` - require(org.Hs.eg.db) - - # error-handling: we need an ENSEMBL column - if (!("ENSEMBL" %in% colnames(exprs_df))) { - stop("'ENSEMBL' column expected in exprs_df") - } - - # using the default behavior for 1:many mappings, where only the first one is - # selected - entrez_mappings <- mapIds(org.Hs.eg.db, - keys = exprs_df$ENSEMBL, - column = "ENTREZID", keytype = "ENSEMBL" - ) - - # if this is not returned in the same order as the keys for some reason, stop - if (!all.equal(names(entrez_mappings), exprs_df$ENSEMBL)) { - stop("Something happened to the gene order!") - } - - # annotation with Entrez IDs - entrez_exprs_df <- exprs_df %>% - # add a new column that contains the Entrez IDs - # this gets added as the last column - dplyr::mutate(ENTREZID = entrez_mappings) %>% - # drop the Ensembl gene IDs - dplyr::select(-ENSEMBL) %>% - # reorder such that the Entrez IDs are in the first column - dplyr::select(ENTREZID, dplyr::everything()) %>% - # drop any genes without an Entrez ID - dplyr::filter(!is.na(ENTREZID)) - - # if there are any duplicate Entrez gene IDs, collapse to the mean value - if (any(duplicated(entrez_exprs_df$ENTREZID))) { - message("Collapsing to mean value...") - entrez_exprs_df <- entrez_exprs_df %>% - dplyr::group_by(ENTREZID) %>% - dplyr::summarise_all(mean) - } - - # expression matrix where the rownames are the gene identifiers - exprs_mat <- entrez_exprs_df %>% - tibble::column_to_rownames("ENTREZID") %>% - as.matrix() -} -``` - -### Gene sets - -`qusage` allows you to read in gene sets that are in the [GMT format](http://software.broadinstitute.org/cancer/software/gsea/wiki/index.php/Data_formats#GMT:_Gene_Matrix_Transposed_file_format_.28.2A.gmt.29). -[MSigDB](http://software.broadinstitute.org/gsea/msigdb) offers gene sets in this format. - -For more information or recommendations about gene sets, [see the **Gene Sets** -section of the module README](https://github.com/AlexsLemonade/refinebio-examples/tree/master/pathway-analysis#choosing-gene-sets). - -We need to download the the MSigDB v6.2 KEGG gene sets that use Entrez gene IDs -and place them at the following relative path: - -``` -gene-sets/c2.cp.kegg.v6.2.entrez.gmt -``` - -We can download the file if it's not available locally yet. - -```{r} -# the kegg gmt file should be located in the spot we mention above -kegg_file <- file.path("gene-sets", "c2.cp.kegg.v6.2.entrez.gmt") -# since we do not track this file in our repository, let's check to make sure -# it exists where we expect it and download it if we don't find it -if (!file.exists(kegg_file)) { - message(paste( - "KEGG GMT file is not found at", kegg_file, - ", downloading now..." - )) - # need gene-sets directory - if (!dir.exists("gene-sets")) { - dir.create("gene-sets") - } - download.file("https://data.broadinstitute.org/gsea-msigdb/msigdb/release/6.2/c2.cp.kegg.v6.2.entrez.gmt", - destfile = kegg_file - ) -} -``` - -## Read in and prep refine.bio data - -### Northcott et al. - -This dataset is too large to be tracked with git without compression. -We need to unzip it here if we have not already. -Note that if your file is not zipped you can skip this chunk. - -```{r} -# if the unzipped folder does not exist -- skip this if you do not have a zipped file -if (!dir.exists(file.path( - data_dir, - "GSE37382" # Replace with the name of your file without the .zip extension -))) { - compressed_file <- file.path( - data_dir, - "GSE37382.zip" # Replace with the name of your zipped file - ) - unzip(compressed_file, exdir = data_dir) -} -``` - -#### Expression data - -```{r} -northcott_dir <- file.path( - data_dir, - "GSE37382" # Replace with name of the folder in which your northcott expression file is stored -) -northcott_expression_file <- file.path( - northcott_dir, - "GSE37382.tsv" # Replace with name of your northcott expression file -) -northcott_exprs_df <- readr::read_tsv(northcott_expression_file, - progress = FALSE -) -# first column is currently named 'Gene' and contains Ensembl gene IDs -colnames(northcott_exprs_df)[1] <- "ENSEMBL" -``` - -Convert to expression matrix that uses Entrez IDs as rownames using a -[custom function](#function). - -```{r} -northcott_mat <- convert_ensembl_to_entrez_mat(northcott_exprs_df) -``` - -We no longer need the `data.frame` that contains the expression values. - -```{r} -rm(northcott_exprs_df) -``` - -#### Metadata - -```{r} -northcott_metadata_file <- file.path( - northcott_dir, - "metadata_GSE37382.tsv" # Replace with name of your northcott metadata file -) -northcott_metadata_df <- readr::read_tsv(northcott_metadata_file) %>% - # drop columns that are all NA - dplyr::select(-which(apply(is.na(.), 2, all))) -``` - -We're going to compare the SHH subgroup to all others, so we need to encode -this information in a new column (`shh_v_other`). - -```{r} -northcott_metadata_df <- northcott_metadata_df %>% - # retain only pertinent columns - dplyr::select( - refinebio_accession_code, refinebio_title, refinebio_age, - refinebio_sex, subgroup - ) %>% - # new column that sets up pathway analysis - dplyr::mutate(shh_v_other = dplyr::case_when( - subgroup != "SHH" ~ "Other", - TRUE ~ "SHH" - )) -``` - -Reorder expression matrix to match the metadata. - -```{r} -northcott_mat <- northcott_mat[, northcott_metadata_df$refinebio_accession_code] -``` - -### Robinson et al. - -#### Expression data - -```{r} -robinson_dir <- file.path( - data_dir, - "GSE37418" # Replace with name of the folder in which your robinson expression file is stored -) -robinson_expression_file <- file.path( - robinson_dir, - "GSE37418.tsv" # Replace with name of your robinson expression file -) -robinson_exprs_df <- readr::read_tsv(robinson_expression_file, - progress = FALSE -) -colnames(robinson_exprs_df)[1] <- "ENSEMBL" -``` - -Convert to expression matrix that uses Entrez IDs as rownames using a -[custom function](#function). - -```{r} -robinson_mat <- convert_ensembl_to_entrez_mat(robinson_exprs_df) -``` - -```{r} -rm(robinson_exprs_df) -``` - -#### Metadata - -```{r} -robinson_metadata_file <- file.path( - robinson_dir, - "metadata_GSE37418.tsv" # Replace with name of your robinson metadata file -) -robinson_metadata_df <- readr::read_tsv(robinson_metadata_file) %>% - # drop columns that are all NA - dplyr::select(-which(apply(is.na(.), 2, all))) -``` - -To make this more comparable to the Northcott et al. dataset, we're going to -remove the WNT subgroup and outliers such that we are comparing the SHH group -to Group 3 and Group 4. - -```{r} -robinson_metadata_df <- robinson_metadata_df %>% - # retain only pertinent columns - dplyr::select( - refinebio_accession_code, refinebio_title, age, `m stage`, - subgroup - ) %>% - # make more comparable to Northcott dataset - dplyr::filter(!(subgroup %in% c("WNT", "SHH OUTLIER", "U"))) %>% - # we'll use SHH vs. Other for our pathway analysis - dplyr::mutate(shh_v_other = dplyr::case_when( - subgroup != "SHH" ~ "Other", - TRUE ~ "SHH" - )) -``` - -Reorder expression data to match metadata. - -```{r} -robinson_mat <- robinson_mat[, robinson_metadata_df$refinebio_accession_code] -``` - -## Pathway analysis - -### Read in KEGG pathways - -```{r} -kegg_pathways <- read.gmt(kegg_file) -``` - -### Northcott et al. - -```{r} -northcott_results <- qusage( - eset = northcott_mat, - labels = northcott_metadata_df$shh_v_other, - contrast = "SHH-Other", - geneSets = kegg_pathways -) -``` - -Save the Northcott et al. results to file. - -```{r} -northcott_results_file <- file.path( - results_dir, - "Northcott_SHH-Other_QSarray.RDS" # Replace with a relevant output name for the first results RDS file -) -readr::write_rds(northcott_results, northcott_results_file) -``` - -### Robinson et al. - -```{r} -robinson_results <- qusage( - eset = robinson_mat, - labels = robinson_metadata_df$shh_v_other, - contrast = "SHH-Other", - geneSets = kegg_pathways -) -``` - -Save the Robinson et al. results to file. - -```{r} -robinson_results_file <- file.path( - results_dir, - "Robinson_SHH-Other_QSarray.RDS" # Replace with a relevant output name for the second results RDS file -) -readr::write_rds(robinson_results, robinson_results_file) -``` - -## Meta-analysis - -### Combine probability density function - -`combinePDFs` is a `qusage` function we can use for meta-analysis. -This function accepts a list of `QSArray` results. - -```{r} -results_list <- list( - Northcott = northcott_results, - Robinson = robinson_results -) -``` - -Because there are more samples in the Northcott et al. dataset, it will be -weighted more highly when combining the distribution. - -```{r} -combined_results <- combinePDFs(results_list) -``` - -Just as in a single dataset, we can extract relevant information from -the combined `QSArray` with built-in `qusage` functions. - -Let's look at the top 20 pathways with `qsTable`. -The row numbers in the output of `qsTable` can serve as input to the -`path.index` argument of other `qusage` functions as we'll see below. - -```{r} -qsTable(combined_results) -``` - -### Plotting - -We can plot the distributions with `plotCombinedPDF`. -First let's plot KEGG Pathways in Cancer, which has elevated expression in -the SHH group as it has a _positive_ fold change. -In a two group comparison in QuSAGE, **pathway activity** is the mean difference -of the log expression of all genes in a pathway. - -```{r} -plotCombinedPDF(combined_results, path.index = 162) -legend("topleft", - legend = c("Northcott", "Robinson", "Meta-analysis"), - lty = 1, col = c("#E41A1C", "#377EB8", "black") -) -``` - -The positive pathway activity curves indicate that the genes in this -pathway have higher expression values in the SHH group for both datasets. -The pathway activity (mean difference) in the Northcott dataset which has -a larger sample size. - -Let's plot KEGG Dorsoventral Axis Formation, which has higher expression in -Group 3 and 4 samples. - -```{r} -plotCombinedPDF(combined_results, path.index = 107) -legend("topleft", - legend = c("Northcott", "Robinson", "Meta-analysis"), - lty = 1, col = c("#E41A1C", "#377EB8", "black") -) -``` - -#### Plot individual gene mean and 95% confidence intervals (CI) - -We know that the directionality of the KEGG Dorsoventral Axis Formation pathway -agrees between datasets. -We can look into what genes are driving the pathway activity with the -`plotCIsGenes` function. -Gene activity, which will be plotted on the y-axis, is difference between the -two groups. -The _pathway_ CI will also be displayed on the plot as a gray band by default. - -```{r} -plotCIsGenes(northcott_results, - path.index = 107, addGrid = FALSE, - cex.xaxis = 1.25 -) -``` - -We can see that, in the Northcott dataset, there are about 5 genes really -driving the negative pathway activity. -Let's take a look at the same pathway in Robinson. - -```{r} -plotCIsGenes(robinson_results, - path.index = 107, addGrid = FALSE, - cex.xaxis = 1.25 -) -``` - -Looks like some of the top genes are the same between datasets: `56907`, `56776` -Because Entrez IDs are not particularly human-readable, we can use the same -annotation package to convert these to gene symbols and gene names. - -```{r} -AnnotationDbi::select(org.Hs.eg.db, - keys = c("56907", "56776"), - keytype = "ENTREZID", columns = c("SYMBOL", "GENENAME") -) -``` - -It looks like these two genes promote the polymerization of actin filaments. - -## Session Info - -```{r} -sessioninfo::session_info() -``` diff --git a/02-microarray/pathway-analysis_microarray_04_qusage_replicate_vignette.Rmd b/02-microarray/pathway-analysis_microarray_04_qusage_replicate_vignette.Rmd deleted file mode 100644 index 397a6b3d..00000000 --- a/02-microarray/pathway-analysis_microarray_04_qusage_replicate_vignette.Rmd +++ /dev/null @@ -1,465 +0,0 @@ ---- -title: "Pathway analysis with QuSAGE: Replicate vignette" -output: - html_notebook: - toc: TRUE - toc_float: TRUE -author: J. Taroni for ALSF CCDL -date: 2019 ---- - -## Background - -Here, we will replicate the [`qusage` package vignette](https://bioconductor.org/packages/release/bioc/vignettes/qusage/inst/doc/qusage.pdf) ( C.). -Specifically, we'll use the same dataset and analysis as the vignette, but the -expression data and sample metadata we will use is processed with refine.bio. -This allows us to explore formatting refine.bio datasets for use with -`qusage` and to compare the results using refine.bio data to the -results in the package vignette. -We will briefly cover how to obtain gene sets for pathway analysis from the -[Molecular Signatures Database (MSigDB)](http://software.broadinstitute.org/gsea/msigdb) -as well. - -## Pathway analysis - -### Set up - -```{r} -# Set seed -set.seed(12345) - -`%>%` <- dplyr::`%>%` -``` - -We need to install `qusage` if we have not already done so. -We'll need `org.Hs.eg.db` as well. - -```{r} -if (!("qusage" %in% installed.packages())) { - BiocManager::install("qusage", update = FALSE) -} - -if (!("org.Hs.eg.db" %in% installed.packages())) { - BiocManager::install("org.Hs.eg.db", update = FALSE) -} -``` - -```{r} -library(org.Hs.eg.db) -library(qusage) -``` - -Make directories to hold the plots and results. - -```{r} -# Define the file path to the plots directory -plots_dir <- "plots" # Replace with path to desired output plots directory - -# Make a plots directory if it isn't created yet -if (!dir.exists(plots_dir)) { - dir.create(plots_dir) -} - -# Define the file path to the results directory -results_dir <- "results" # Replace with path to desired output results directory - -# Make a results directory if it isn't created yet -if (!dir.exists(results_dir)) { - dir.create(results_dir) -} - -# Define the file path to the data directory -data_dir <- "data" -``` - -### Gene sets - -`qusage` allows you to read in gene sets that are in the [GMT format](http://software.broadinstitute.org/cancer/software/gsea/wiki/index.php/Data_formats#GMT:_Gene_Matrix_Transposed_file_format_.28.2A.gmt.29). -[MSigDB](http://software.broadinstitute.org/gsea/msigdb) offers gene sets in this format. - -We need to download the the MSigDB v6.2 KEGG gene sets that use Entrez gene IDs and placed them at the following relative path: - -``` -gene-sets/c2.cp.kegg.v6.2.entrez.gmt -``` - -We can download the file if we don't find it where we expect! - -```{r} -# the kegg gmt file should be located in the spot we mention above -kegg_file <- file.path("gene-sets", "c2.cp.kegg.v6.2.entrez.gmt") -# since we do not track this file in our repository, let's check to make sure -# it exists where we expect it and download it if we don't find it -if (!file.exists(kegg_file)) { - message(paste( - "KEGG GMT file is not found at", kegg_file, - ", downloading now..." - )) - # need gene-sets directory - if (!dir.exists("gene-sets")) { - dir.create("gene-sets") - } - download.file("https://data.broadinstitute.org/gsea-msigdb/msigdb/release/6.2/c2.cp.kegg.v6.2.entrez.gmt", - destfile = kegg_file - ) -} -``` - -### Conversion to Entrez gene IDs - -All refine.bio data uses Ensembl gene IDs. -As noted above, the gene sets we'll be using for our pathway analysis use -Entrez gene identifiers. -As a result, we'll need to convert the expression data identifiers to Entrez -IDs. - -```{r} -# read in gene expression data -expression_file <- file.path( - data_dir, - "GSE30550", # Replace with name of the folder in which your expression file is stored - "GSE30550.tsv" # Replace with name of your expression file -) -exprs_df <- readr::read_tsv(expression_file, progress = FALSE) -# first column is currently named 'Gene' and contains Ensembl gene IDs -colnames(exprs_df)[1] <- "ENSEMBL" -``` - -We're using the default behavior for 1:many mappings, where only the first one -is selected ([docs](https://www.rdocumentation.org/packages/AnnotationDbi/versions/1.30.1/topics/AnnotationDb-objects)). - -```{r} -entrez_mappings <- mapIds(org.Hs.eg.db, - keys = exprs_df$ENSEMBL, - column = "ENTREZID", keytype = "ENSEMBL" -) -``` - -```{r} -all.equal(names(entrez_mappings), exprs_df$ENSEMBL) -``` - -We'll add this to the `data.frame` of expression data and save to file. - -```{r} -exprs_df <- exprs_df %>% - dplyr::mutate(ENTREZID = entrez_mappings) %>% - dplyr::select(ENTREZID, ENSEMBL, dplyr::everything()) -readr::write_tsv(exprs_df, - path = file.path( - data_dir, - "GSE30550", # Replace with name of the folder in which tour expression data is stored - "GSE30550_entrez.tsv" # Replace with name of your expression file containing Entrez gene IDs - ) -) -``` - -### Read in metadata and filter - -```{r} -metadata_file <- file.path( - data_dir, - "GSE30550", # Replace with name of the folder in which your relevant metadata is stored - "metadata_GSE30550.tsv" # Replace with name of the metadata file relevant to your expression file -) -metadata_df <- readr::read_tsv(metadata_file) %>% - # drop columns that are all NA - dplyr::select(-which(apply(is.na(.), 2, all))) -``` - -In the `qusage` vignette, the authors compared samples 0 hours after exposure to -influenza and sample 77 hours after exposure to influenza. -We'll subset to just these samples. - -```{r} -filtered_metadata_df <- metadata_df %>% - dplyr::filter(time_hpi %in% c("Hour 00", "Hour 077")) %>% - # the subject & timepoint info are combined in the 'title' column - dplyr::mutate( - subject = stringr::word(title, 1, sep = ","), - # relabel the timepoints, the lack of spaces will help - # with the contrast call later - timepoint = dplyr::case_when( - time_hpi == "Hour 00" ~ "t0", - time_hpi == "Hour 077" ~ "t1" - ) - ) %>% - dplyr::arrange(time_hpi, subject) %>% - dplyr::select( - refinebio_accession_code, subject, refinebio_title, class_blu, - clinic_pheno, time_hpi, timepoint - ) -``` - -```{r} -time_filtered_exprs <- exprs_df %>% - dplyr::select(-ENSEMBL) %>% - # we're reordering samples here to match the metadata ordering - dplyr::select(ENTREZID, filtered_metadata_df$refinebio_accession_code) -``` - -Are there duplicated identifiers? - -```{r} -anyDuplicated(time_filtered_exprs$ENTREZID) -``` - -Collapse to duplicated gene identifiers to their mean values. - -```{r} -collapsed_exprs <- time_filtered_exprs %>% - dplyr::group_by(ENTREZID) %>% - dplyr::summarise_all(mean) %>% - # drop unannotated gene - dplyr::filter(!is.na(ENTREZID)) -``` - -We need to pass `qusage` a matrix. -Note that we're departing a bit from the advice of the authors by -refraining from filtering the expression matrix. - -```{r} -exprs_mat <- collapsed_exprs %>% - tibble::column_to_rownames("ENTREZID") %>% - as.matrix() -``` - -Let's get rid of some of the objects in the workspace we don't need. - -```{r} -rm(collapsed_exprs, time_filtered_exprs, exprs_df, metadata_df) -``` - -### Read in gene sets - -```{r} -kegg_genesets <- read.gmt(kegg_file) -``` - -### Perform pathway analysis - -```{r} -timepoint_qusage_results <- qusage( - eset = exprs_mat, - labels = filtered_metadata_df$timepoint, - contrast = "t1-t0", - geneSets = kegg_genesets -) -``` - -We can look at the results with the `qsTable` function. -This will give us the top 20 pathways by default. -(This can be changed via the `number` argument to `qsTable`.) - -```{r} -qsTable(timepoint_qusage_results) -``` - -Let's save the results to file. -First, let's save a nicely formatted table. - -```{r} -timepoint_table <- qsTable(timepoint_qusage_results, - # numPathways let's us snag all tested gene sets - number = numPathways(timepoint_qusage_results) -) -readr::write_tsv( - timepoint_table, - file.path(results_dir, "qusage_t1-t0_kegg_results.tsv") -) -``` - -Note that gene sets with negative fold changes are higher in `t0`. - -We're also going to save the `QSarray` output of `qusage` because, as we'll see -shortly, there's lots you can do with qusage results! - -```{r} -readr::write_rds( - timepoint_qusage_results, - file.path(results_dir, "qusage_t1-t0_kegg_QSarray.RDS") -) -``` - -#### Plotting - -We can look at the overall results with the `plotCIs` function. - -```{r} -plotCIs(timepoint_qusage_results, cex.xaxis = 0.25) -``` - -It's a bit difficult to see in this notebook, but we'll save the plot as a PDF. - -```{r} -pdf(file.path(plots_dir, "qusage_t1-t0_plotCIs.pdf"), width = 14, height = 8) -# adjusting the figure margins to better fit pathway names -par(mar = c(8, 4, 1, 2)) -plotCIs(timepoint_qusage_results, cex.xaxis = 0.5) -dev.off() -``` - -Let's look more closely at the T Cell Receptor Signaling Pathway. -We can see above that this pathway has a negative fold change and therefore -should be higher at `t0`. - -```{r} -pathway_index <- - which(names(kegg_genesets) == "KEGG_T_CELL_RECEPTOR_SIGNALING_PATHWAY") # Replace with exact name of desired pathway -- names of pathways can be seen using the `names(kegg_genesets)` function -``` - -Plot the overall distribution of the pathway (thick black line) and the -distribution of the individual genes (thin lines colored by their standard -deviations). - -```{r} -plotGeneSetDistributions(timepoint_qusage_results, path.index = pathway_index) -``` - -We can see the majority of genes in this pathway don't change much, but a -handful have lower values in `t1`. - -Now, plot the mean and confidence intervals for each gene in the pathway. -This gives us insight into _which_ genes changed the most. - -```{r} -plotCIsGenes(timepoint_qusage_results, - path.index = pathway_index, - cex.xaxis = 0.75 -) -``` - -We can easily check to see if the directionality is as we expect by making -a boxplot of the gene `387` which has a negative value and is on right side of -the graph. - -```{r} -graphics::boxplot(exprs_mat["387", ] ~ filtered_metadata_df$timepoint) -``` - -### Two-way comparison - -Patients in this influenza data set were either _symptomatic_ or _asymptomatic_. -We can check if there are differences in pathway _responses_ to influenza virus -(e.g., between time points) between the two groups. -The ability to do this more complex comparison is a great feature of `qusage`. -Again, we'll mirror the analysis performed in the vignette. - -The symptomatic or asymptomatic information is in the `clinic_pheno` column -of the metadata. - -```{r} -head(filtered_metadata_df$clinic_pheno) -``` - -Generate labels for the two-way comparison. - -```{r} -two_way_labels <- paste(filtered_metadata_df$clinic_pheno, - filtered_metadata_df$timepoint, - sep = "." -) -two_way_labels -``` - -Symptomatic comparison - -```{r} -sx_results <- qusage( - eset = exprs_mat, - labels = two_way_labels, - contrast = "Symptomatic.t1-Symptomatic.t0", - geneSets = kegg_genesets, - # timepoints are paired samples, so we can specify that - # information here - pairVector = filtered_metadata_df$subject -) -``` - -Asymptomatic comparison - -```{r} -asx_results <- qusage( - eset = exprs_mat, - labels = two_way_labels, - contrast = "Asymptomatic.t1-Asymptomatic.t0", - geneSets = kegg_genesets, - pairVector = filtered_metadata_df$subject -) -``` - -Calculate the difference between the two comparisons - -```{r} -sx_vs_asx <- qusage( - eset = exprs_mat, - labels = two_way_labels, - contrast = "(Symptomatic.t1-Symptomatic.t0) - (Asymptomatic.t1-Asymptomatic.t0)", - geneSets = kegg_genesets, - pairVector = filtered_metadata_df$subject -) -``` - -Let's look at the cytosolic DNA sensing pathway like the authors' do in the -vignette and see if we get similar results. - -```{r} -names(kegg_genesets)[125] -``` - -```{r} -plotDensityCurves(asx_results, - path.index = 125, - col = "#D55E00", - main = "CYTOSOLIC DNA SENSING", - xlim = c(-1.0, 2.5) -) -plotDensityCurves(sx_results, path.index = 125, col = "#56B4E9", add = TRUE) -plotDensityCurves(sx_vs_asx, - path.index = 125, col = "#000000", add = TRUE, - lwd = 3 -) -legend("topleft", - legend = c("Asymptomatic", "Symptomatic", "Symptomatic-Asymptomatic"), - lty = 1, col = c("#D55E00", "#56B4E9", "#000000", lwd = c(1, 1, 3)), - cex = 0.5 -) -``` - -This tells us that this pathway is active in the Symptomatic patients, but -not much is happening in the Asymptomatic patients. -This is the result in the vignette, although the magnitude of the values (`x`) -are different. - -```{r} -plotGeneSetDistributions(sx_results, asx_results, path.index = 125) -``` - -A few genes appear to be driving the elevation of the cytosolic DNA sensing -patients in symptomatic patients after exposure (`t1`). -We can take a closer look with `plotCIsGenes`. - -```{r} -plotCIsGenes(sx_results, path.index = 125) -``` - -Let's look at the Asymptomatic results, where we'd expect no difference between -timepoints for most of the genes based on the plots above. - -```{r} -plotCIsGenes(asx_results, path.index = 125) -``` - -We expect the gene `3665` ([_IRF7_](https://www.genecards.org/cgi-bin/carddisp.pl?gene=IRF7&keywords=3665)) -to be elevated in `t1` compared to `t0` but _only_ in Symptomatic patients. -Let's make a boxplot to be sure. - -```{r} -graphics::boxplot(exprs_mat["3665", ] ~ interaction(filtered_metadata_df$timepoint, filtered_metadata_df$clinic_pheno)) -``` - -## Session info - -```{r} -sessioninfo::session_info() -``` diff --git a/02-microarray/pathway-analysis_microarray_05_qusage_single_dataset.Rmd b/02-microarray/pathway-analysis_microarray_05_qusage_single_dataset.Rmd deleted file mode 100644 index 864f1dc3..00000000 --- a/02-microarray/pathway-analysis_microarray_05_qusage_single_dataset.Rmd +++ /dev/null @@ -1,481 +0,0 @@ ---- -title: "Pathway analysis with QuSAGE: Single dataset" -output: - html_notebook: - toc: TRUE - toc_float: TRUE -author: J. Taroni for ALSF CCDL -date: 2019 ---- - -## Background - -In this module, we'll demonstrate how to perform pathway analysis using -Quantitative Set Analysis of Gene Expression (QuSAGE) -([](https://doi.org/10.1093/nar/gkt660)). -QuSAGE, implemented in the [`qusage` bioconductor package](https://bioconductor.org/packages/release/bioc/html/qusage.html), -has some nice features: - -* It takes into account inter-gene correlation (a source of type I error). -* It returns more information than just a p-value. -That's useful for analyses you might want to perform downstream. -* Built-in visualization functionality. - -We recommend taking a look at the original publication (Yaari et al.) and -the R package documentation to learn more. - -## Gene sets - -`qusage` allows you to read in gene sets that are in the [GMT format](http://software.broadinstitute.org/cancer/software/gsea/wiki/index.php/Data_formats#GMT:_Gene_Matrix_Transposed_file_format_.28.2A.gmt.29). -[Curated gene sets from MSigDB](http://software.broadinstitute.org/gsea/msigdb/collections.jsp#C2) -like [KEGG](https://www.genome.jp/kegg/) are popular for pathway analysis, but -MSigDB only distributes human pathway data. -Here, we'll work with a mouse dataset. - -In the [`kegg_ortholog_mapping`](./kegg_ortholog_mapping.nb.html) notebook in -this module, we mapped human Entrez IDs to mouse symbols using the -[`hcop` package](https://github.com/stephenturner/hcop). -When there was a 1:many mapping between human Entrez IDs and mouse gene symbols, -we selected the mouse gene symbol with the highest number of resources -supporting the mapping. -This decision might not be suitable for every experiment and may result in -some loss of information. - -## Dataset - -We're using [`GSE75574`](https://www.refine.bio/experiments/GSE75574/gene-expression-in-mouse-tissues-in-response-to-short-term-calorie-restriction) in this notebook. -This dataset assays the gene expression response to short-term calorie -restriction in multiple tissues from multiple mouse strains. -We'll test for pathways that change in response to short-term calorie -restriction. - -## Set up - -Package installation and loading - -```{r} -if (!("qusage" %in% installed.packages())) { - BiocManager::install("qusage", update = FALSE) -} - -if (!("org.Mm.eg.db" %in% installed.packages())) { - BiocManager::install("org.Mm.eg.db", update = FALSE) -} - -if (!("pheatmap" %in% installed.packages())) { - install.packages("pheatmap") -} -``` - -```{r} -`%>%` <- dplyr::`%>%` -``` - -```{r} -library(qusage) -library(org.Mm.eg.db) -library(pheatmap) -``` - -Create directories to hold plots and results if they do not yet exist. - -```{r} -# Define the file path to the plots directory -plots_dir <- "plots" # Replace with path to desired output plots directory - -# Make a plots directory if it isn't created yet -if (!dir.exists(plots_dir)) { - dir.create(plots_dir) -} - -# Define the file path to the results directory -results_dir <- "results" # Replace with path to desired output results directory - -# Make a results directory if it isn't created yet -if (!dir.exists(results_dir)) { - dir.create(results_dir) -} - -# Define the file path to the data directory -data_dir <- "data" -``` - -## Read in refine.bio data - -The gene expression matrix of the dataset we'll be working with is too large -to be tracked with git without compression, so we need to unzip it if we have -not already. - -Note that if your file is not zipped you can skip this chunk. - -```{r} -# if the unzipped folder does not exist -- skip this if you do not have a zipped file -if (!dir.exists(file.path( - data_dir, - "GSE75574" # Replace with the name of your file without the .zip extension -))) { - compressed_file <- file.path( - data_dir, - "GSE75574.zip" # Replace with the name of your zipped file - ) - unzip(compressed_file, exdir = data_dir) -} -``` - -### Expression data - -```{r} -expression_file <- file.path( - data_dir, - "GSE75574", # Replace with name of the folder in which your expression file is stored - "GSE75574.tsv" # Replace with name of your expression file -) -exprs_df <- readr::read_tsv(expression_file, progress = FALSE) -# first column is currently named 'Gene' and contains Ensembl gene IDs -colnames(exprs_df)[1] <- "ENSEMBL" -``` - -Because our gene sets use gene symbols and expression data from refine.bio uses -Ensembl IDs, we need to do a conversion. -We're using the default behavior for 1:many mappings here, where only the first -one is selected -([docs](https://www.rdocumentation.org/packages/AnnotationDbi/versions/1.30.1/topics/AnnotationDb-objects)). - -```{r} -symbol_mappings <- mapIds(org.Mm.eg.db, - keys = exprs_df$ENSEMBL, - column = "SYMBOL", keytype = "ENSEMBL" -) -``` - -```{r} -head(symbol_mappings) -``` - -```{r} -# mapIds returns this in the same order as the keys we passed it to, let's -# demonstrate that -all.equal(names(symbol_mappings), exprs_df$ENSEMBL) -``` - -We'll annotate these expression data with the gene symbols. - -```{r} -symbol_exprs_df <- exprs_df %>% - # add a new column that contains the gene symbols - # this gets added as the last column - dplyr::mutate(SYMBOL = symbol_mappings) %>% - # drop the Ensembl gene IDs - dplyr::select(-ENSEMBL) %>% - # reorder such that the gene symbols are in the first column - dplyr::select(SYMBOL, dplyr::everything()) %>% - # drop any genes without a gene symbol - dplyr::filter(!is.na(SYMBOL)) -``` - -How many gene symbols have duplicate values? - -```{r} -sum(duplicated(symbol_exprs_df$SYMBOL)) -``` - -Collapse to the mean value for that gene symbol. - -```{r} -symbol_exprs_df <- symbol_exprs_df %>% - dplyr::group_by(SYMBOL) %>% - dplyr::summarise_all(mean) -``` - -Write to file. - -```{r} -readr::write_tsv(symbol_exprs_df, file.path( - data_dir, - "GSE75574", # Replace with name of the folder in which you would like to store your output file - "GSE75574_symbols.tsv" # Replace with relevant output name -)) -``` - -### Metadata - -```{r} -metadata_file <- file.path( - data_dir, - "GSE75574", # Replace with name of the folder in which your relevant metadata file is stored - "metadata_GSE75574.tsv" # Replace with name of relevant metadata file -) -metadata_df <- readr::read_tsv(metadata_file) %>% - # drop any metadata columns that are all NAs - dplyr::select(-which(apply(is.na(.), 2, all))) -``` - -Retain only the most pertinent columns. - -```{r} -metadata_df <- metadata_df %>% - dplyr::select( - refinebio_accession_code, refinebio_title, - refinebio_specimen_part, refinebio_sex, strain - ) -``` - -This particular accession ([`GSE75574`](https://www.refine.bio/experiments/GSE75574/gene-expression-in-mouse-tissues-in-response-to-short-term-calorie-restriction)) is a SuperSeries comprised of experiments -in multiple tissues from multiple mouse strains. -We'll use white adipose tissue for all strains in this example. - -```{r} -metadata_df <- metadata_df %>% - dplyr::filter(refinebio_specimen_part == "white adipose") -``` - -The two groups we are interested in for comparison are calorie restricted vs. -controls. -This information is in the title. -We can extract this and put it in its own column called `condition`. - -```{r} -metadata_df <- metadata_df %>% - dplyr::mutate(condition = dplyr::case_when( - grepl("control", refinebio_title) ~ "control", - grepl("calorierestricted", refinebio_title) ~ "calorierestricted" - )) -``` - -## Pathway Analysis - -### Read in KEGG pathways - -First, we need the sets of genes that represent pathways. -Again, these were prepared in the -[`kegg_ortholog_mapping`](./kegg_ortholog_mapping.nb.html) notebook (see -[Gene Sets](#gene-sets) above). - -```{r} -kegg_file <- file.path( - "gene-sets", - "c2.cp.kegg.v6.2.entrez_mouse_symbol_hcop.gmt" -) -kegg_pathways <- read.gmt(kegg_file) -``` - -### Prep expression matrix - -```{r} -exprs_mat <- symbol_exprs_df %>% - tibble::column_to_rownames("SYMBOL") %>% - # same order as the metdata - dplyr::select(metadata_df$refinebio_accession_code) %>% - # qusage takes a matrix - as.matrix() -``` - -We want to compare calorie restricted mice to controls. - -```{r} -qusage_results <- qusage( - eset = exprs_mat, - labels = metadata_df$condition, - contrast = "calorierestricted-control", - geneSets = kegg_pathways -) -``` - -Save the `QSArray` output. -We can use this object for visualization or other downstream analyses. - -```{r} -readr::write_rds( - qusage_results, - file.path( - results_dir, - "GSE75574_adipose_calorierest-ctrl_QSarray.RDS" # Replace with file name relevant to output results - ) -) -``` - -### Overall results - -We can get a look at the general trend of the results with the `plotCIs` -function. -This plots the means and 95% confidence intervals of each pathway we tested, -sorted such that the gene sets with the highest mean will be on the left of the -plot. -These are gene sets that are elevated in calorie restricted mice. -Error bars are colored by the directionality and corrected p-value (FDR by -default). -Unfortunately the p-value color scheme is red-green, which does not work well -for people with green or red color-vision deficiency. - -```{r} -plotCIs(qusage_results, cex.xaxis = 0.25, main = "Calorie Restricted - Control") -``` - -Save to plot. - -```{r} -pdf(file.path( - plots_dir, - "GSE75574_adipose_calorierestricted-control_plotCIs.pdf" -), -width = 14, height = 8.5 -) -plotCIs(qusage_results, cex.xaxis = 0.25, main = "Calorie Restricted - Control") -dev.off() -``` - -We can also look at the log fold-change and FDR values for pathways with the -`qsTable` function. -By default, this function shows you the top 20 pathways sorted by FDR. -We can change the `number` argument to `qsTable` to decrease or increase the -number of pathways returned. -We can use the `numPathways` function to get _all_ the pathways we tested. - -```{r} -qsTable(qusage_results, number = numPathways(qusage_results)) -``` - -Write to results. - -```{r} -qsTable(qusage_results, number = numPathways(qusage_results)) %>% - readr::write_tsv(file.path( - results_dir, - "GSE75574_adipose_calorierestricted-control.tsv" # Replace with file name relevant to results output - )) -``` - -`qusage` has functionality that lets us dig into our results a bit more to -get an idea of which genes are contributing to the differences between our two -groups. - -### KEGG ECM Receptor Interaction - -The KEGG ECM Receptor Interaction pathway expression is reduced in response -to calorie restriction. - -We can look at the distribution of genes in this pathway with the -`plotGeneSetDistributions` function. -We tell this function which pathway to plot with the `path.index` argument. - -```{r} -grep( - "ECM_RECEPTOR", # Replace with an exact word or phrase that would filter in your desired pathway(s) as the `grep` function looks for all instances of the pattern given -- names of pathways can be seen using the `names(kegg_pathways)` function - names(kegg_pathways) -) -``` - -```{r} -plotGeneSetDistributions(qusage_results, path.index = 114) -``` - -_Most_ genes are around zero (no activity), but we see some genes with -negative activity values. -We can dig into the _what_ the genes are with the `plotCIsGenes` function. - -```{r} -plotCIsGenes(qusage_results, path.index = 114) -``` - -Let's look at another example with the opposite directionality. - -### KEGG Steroid Biosynthesis - -The KEGG Steroid Biosynthesis pathway expression is increased in calorie -restricted adipose tissue. - -```{r} -plotGeneSetDistributions(qusage_results, path.index = 9) -``` - -This looks about half of the genes have positive activity values. - -```{r} -plotCIsGenes(qusage_results, path.index = 9) -``` - -We can make a heatmap with only genes from this pathway. -The heatmap will have similar information as `plotCIsGenes`, but we'll also -get a sense of how samples relate to one another. - -#### Heatmap - -Subset the expression matrix to only genes in the KEGG Steroid Biosynthesis -pathways. - -```{r} -steroid_genes <- kegg_pathways$KEGG_STEROID_BIOSYNTHESIS -# rows (genes) in the pathway -steroid_mat <- exprs_mat[which(rownames(exprs_mat) %in% steroid_genes), ] -``` - -We'll use annotation bars for the columns (samples). - -```{r} -# need a data.frame that contains the sample metadata that we're interested in -annotation_col_df <- metadata_df %>% - dplyr::select(refinebio_accession_code, condition, strain) %>% - tibble::column_to_rownames("refinebio_accession_code") - -# colors to be used in the annotation bars -- we need to assign one for -# each factor level in the two columns -annot_colors <- list( - condition = c( - control = "#FFFFFF", - calorierestricted = "#CD2626" - ), - # palette from - # https://github.com/clauswilke/colorblindr/blob/1ac3d4d62dad047b68bb66c06cee927a4517d678/R/palettes.R#L7 - strain = c( - `129S1/SvImJ` = "#E69F00", - `B6C3F1/J` = "#56B4E9", - `Balbc/J` = "#009E73", - `C3H/HeJ` = "#F0E442", - `C57BL6/J` = "#0072B2", - `CBA/J` = "#D55E00", - `DBA/2J` = "#CC79A7" - ) -) -``` - -Let's make the heatmap with annotation bars. - -```{r} -hm_plot <- pheatmap::pheatmap(steroid_mat, - # using blue, white, red color scheme - color = colorRampPalette(c( - "#0000FF", "#FFFFFF", - "#FF0000" - ))(25), - clustering_distance_cols = "correlation", - clustering_distance_rows = "correlation", - clustering_method = "average", - # scale the expression values of genes for - # visualization - scale = "row", - fontsize_col = 2, - angle_col = "45", - annotation_col = annotation_col_df, - annotation_colors = annot_colors, - main = "KEGG Steroid Biosynthesis" -) -``` - -Save the plot. - -```{r} -pdf(file.path( - plots_dir, - "GSE75574_steroid_biosynthesis_heatmap.pdf" # Replace with relevant output plot name -), -width = 7, height = 5 -) -print(hm_plot) -dev.off() -``` - -## Session info - -```{r} -sessioninfo::session_info() -``` diff --git a/02-microarray/pathway-analysis_microarray_06_ssgsea.Rmd b/02-microarray/pathway-analysis_microarray_06_ssgsea.Rmd deleted file mode 100644 index 18d4da57..00000000 --- a/02-microarray/pathway-analysis_microarray_06_ssgsea.Rmd +++ /dev/null @@ -1,445 +0,0 @@ ---- -title: "Pathway analysis: ssGSEA" -output: - html_notebook: - toc: TRUE - toc_float: TRUE -author: J. Taroni for ALSF CCDL -date: 2019 ---- - -## Background - -Pathway or gene set analysis methods like Quantitative Set Analysis of Gene -Expression (QuSAGE) -([](https://doi.org/10.1093/nar/gkt660)) or Gene Set -Enrichment Analysis (GSEA) -([ et al. _PNAS_. 2005.](https://doi.org/10.1073/pnas.0506580102)) -require us to specify group labels. -We may want a better idea of what pathways are up- or down-regulated in -_individual samples_ if we, for example, suspect that there are subgroups of -patients during exploratory data analysis. -We can use single-sample GSEA (ssGSEA) -([Barbie et al. _Nature_. 2009.](https://dx.doi.org/10.1038/nature08460)), -which is implemented in the -[`GSVA` bioconductor package](https://bioconductor.org/packages/release/bioc/html/GSVA.html). -Note that `GSVA` contains _multiple_ gene set enrichment methods and has an -excellent [vignette](https://bioconductor.org/packages/release/bioc/vignettes/GSVA/inst/doc/GSVA.pdf). - -## Gene sets - -We will use KEGG (Kyoto Encyclopedia of Genes and Genomes) Pathways in this -analysis. -We acquired the KEGG `v6.2` pathway set that used human Entrez IDs from the -[Molecular Signatures Database (MSigDB)](http://software.broadinstitute.org/gsea/msigdb). - -In the [`kegg_ortholog_mapping`](./kegg_ortholog_mapping.nb.html) notebook in -this module, we mapped human Entrez IDs to mouse symbols using the -[`hcop` package](https://github.com/stephenturner/hcop). -When there was a 1:many mapping between human Entrez IDs and mouse gene symbols, -we selected the mouse gene symbol with the highest number of resources -supporting the mapping. -This decision might not be suitable for every experiment and may result in -some loss of information. - -## Dataset - -We're using [`GSE75574`](https://www.refine.bio/experiments/GSE75574/gene-expression-in-mouse-tissues-in-response-to-short-term-calorie-restriction) -in this notebook. -This dataset assays the gene expression response to short-term calorie -restriction in multiple tissues from multiple mouse strains. -This is the same dataset we used in one of our QuSAGE examples -([`qusage_single_dataset`](./qusage_single_dataset.nb.html)), where we only -looked at white adipose tissue. - -## Set up - -Package installation and loading. - -```{r} -if (!("qusage" %in% installed.packages())) { - BiocManager::install("qusage", update = FALSE) -} - -if (!("org.Mm.eg.db" %in% installed.packages())) { - BiocManager::install("org.Mm.eg.db", update = FALSE) -} - -if (!("GSVA" %in% installed.packages())) { - BiocManager::install("GSVA", update = FALSE) -} - -if (!("matrixStats" %in% installed.packages())) { - install.packages("matrixStats") -} -``` - -```{r} -`%>%` <- dplyr::`%>%` -``` - -```{r} -library(org.Mm.eg.db) -library(GSVA) -``` - -Create directories to hold plots and results if they do not yet exist. - -```{r} -# Define the file path to the plots directory -plots_dir <- "plots" # Replace with path to desired output plots directory - -# Make a plots directory if it isn't created yet -if (!dir.exists(plots_dir)) { - dir.create(plots_dir) -} - -# Define the file path to the results directory -results_dir <- "results" # Replace with path to desired output results directory - -# Make a results directory if it isn't created yet -if (!dir.exists(results_dir)) { - dir.create(results_dir) -} - -# Define the file path to the data directory -data_dir <- "data" -``` - -## Read in refine.bio data - -The gene expression matrix of the dataset we'll be working with is too large -to be tracked with git without compression, so we need to unzip it if we have -not already. -This compressed folder contains both the expression matrix and the metadata. - -```{r} -# if the unzipped folder does not exist -if (!dir.exists(file.path( - data_dir, - "GSE75574" # Replace with the name of your file without the .zip extension -))) { - compressed_file <- file.path( - data_dir, - "GSE75574.zip" # Replace with the name of your zipped file - ) - unzip(compressed_file, exdir = data_dir) -} -``` - -### Expression data - -Because we used this in another notebook, it's possible that you already have -a local copy of the prepared expression matrix. -If a local copy exists, we don't want to go through the steps to reprocess it, -so we can check for this first. - -If not, we'll process the data in the following ways: - -* Convert the Ensembl gene IDs that are used in refine.bio data to gene symbols. -* If duplicate gene symbols exist, we'll collapse to the mean value for that -gene symbol. - -```{r} -# check for the existence of the file that would have been generated in the -# other notebook -symbol_file <- file.path( - data_dir, - "GSE75574", # Replace with name of your unzipped folder - "GSE75574_symbols.tsv" # Replace with relevant output name -) -if (file.exists(symbol_file)) { - symbol_exprs_df <- readr::read_tsv(symbol_file, progress = FALSE) -} else { - - # read in the refine.bio expression data - expression_file <- file.path( - data_dir, - "GSE75574", # Replace with name of your unzipped folder - "GSE75574.tsv" # Replace with name of your expression file - ) - exprs_df <- readr::read_tsv(expression_file, progress = FALSE) - # first column is currently named 'Gene' and contains Ensembl gene IDs - colnames(exprs_df)[1] <- "ENSEMBL" - - # using the default behavior for 1:many mappings here -- select the first one - symbol_mappings <- mapIds(org.Mm.eg.db, - keys = exprs_df$ENSEMBL, - column = "SYMBOL", keytype = "ENSEMBL" - ) - - # mapIds should give us back IDs in the same order as the keys, but we can - # check to be sure - if (!(all.equal(names(symbol_mappings), exprs_df$ENSEMBL))) { - stop("Gene order is not as expected!") - } - - symbol_exprs_df <- exprs_df %>% - # add a new column that contains the gene symbols - # this gets added as the last column - dplyr::mutate(SYMBOL = symbol_mappings) %>% - # drop the Ensembl gene IDs - dplyr::select(-ENSEMBL) %>% - # reorder such that the gene symbols are in the first column - dplyr::select(SYMBOL, dplyr::everything()) %>% - # drop any genes without a gene symbol - dplyr::filter(!is.na(SYMBOL)) - - # if there are any duplicate gene symbols, collapse to the mean value - if (any(duplicated(symbol_exprs_df$SYMBOL))) { - symbol_exprs_df <- symbol_exprs_df %>% - dplyr::group_by(SYMBOL) %>% - dplyr::summarise_all(mean) - } - - # write to file - readr::write_tsv(symbol_exprs_df, symbol_file) -} -``` - -### Metadata - -```{r} -metadata_file <- file.path( - data_dir, - "GSE75574", # Replace with name of your unzipped folder - "metadata_GSE75574.tsv" # Replace with name of relevant metadata file -) -metadata_df <- readr::read_tsv(metadata_file) %>% - # drop any metadata columns that are all NAs - dplyr::select(-which(apply(is.na(.), 2, all))) -``` - -Retain only the most pertinent columns. - -```{r} -metadata_df <- metadata_df %>% - dplyr::select( - refinebio_accession_code, refinebio_title, - refinebio_specimen_part, refinebio_sex, strain - ) -``` - -We're interested in the are calorie-restricted vs. controls information, which -is in the sample title. -We can extract this and put it in its own column called `condition` as is good -practice. - -```{r} -metadata_df <- metadata_df %>% - dplyr::mutate(condition = dplyr::case_when( - grepl("control", refinebio_title) ~ "control", - grepl("calorierestricted", refinebio_title) ~ "calorie-restricted" - )) -``` - -## Pathway Analysis - -### Read in KEGG pathways - -First, we need the sets of genes that represent pathways. -Again, these were prepared in the -[`kegg_ortholog_mapping`](./kegg_ortholog_mapping.nb.html) notebook (see -[Gene Sets](#gene-sets) above). - -```{r} -kegg_file <- file.path( - "gene-sets", - "c2.cp.kegg.v6.2.entrez_mouse_symbol_hcop.gmt" -) -kegg_pathways <- qusage::read.gmt(kegg_file) -``` - -### Prep expression matrix - -```{r} -exprs_mat <- symbol_exprs_df %>% - tibble::column_to_rownames("SYMBOL") %>% - # same order as the metdata -- this may be helpful in downstream analyses - dplyr::select(metadata_df$refinebio_accession_code) %>% - # qusage takes a matrix - as.matrix() -``` - -### ssGSEA - -We can specify that we'd like to perform ssGSEA with the `method` argument to -`gsva`. - -```{r} -ssgsea_results <- gsva( - expr = exprs_mat, - gset.idx.list = kegg_pathways, - method = "ssgsea", - verbose = FALSE -) -``` - -This returns a matrix of ssGSEA enrichment scores where the columns are samples -and the rows are the input gene sets. - -```{r} -str(ssgsea_results) -``` - -#### Identifying "interesting" features - -One way to figure out what pathways may be interesting is to find which pathways -have the highest _variance_ in their ssGSEA scores. -We can calculate the row variances with the `matrixStats` package. - -```{r} -score_row_var <- matrixStats::rowVars(ssgsea_results) -# for convenience, let's use the pathway names with this vector -names(score_row_var) <- rownames(ssgsea_results) -# look at the 'top' pathways by this metric -head(sort(score_row_var, decreasing = TRUE)) -``` - -Note that many of these pathways seem to have something to do with the immune -system and may very well share a large number of genes. -Let's look at an example pair of these pathways. - -```{r} -intersect( - kegg_pathways$KEGG_ALLOGRAFT_REJECTION, - kegg_pathways$KEGG_GRAFT_VERSUS_HOST_DISEASE -) -``` - -These ssGSEA scores should not be treated as if they are independent. - -#### Plotting features - -What do the patterns across strains and tissues look like? -Let's look at the KEGG Complement and Coagulation Cascades pathway as an -example. - -We'll be using `ggplot2` for plotting, so we'll want our ssGSEA values as a -`data.frame`. - -```{r} -comp_coag_df <- data.frame( - sample_accession = colnames(ssgsea_results), - ssgsea_score = ssgsea_results["KEGG_COMPLEMENT_AND_COAGULATION_CASCADES", ] # Replace with desired pathway -- note that this is distinct from `grep` in that you'd have to write the name exactly as it is in the matrix -) -``` - -We need to add in the strain, tissue, and condition metadata to make an -informative plot. - -```{r} -comp_coag_df <- metadata_df %>% - dplyr::inner_join(comp_coag_df, - by = c("refinebio_accession_code" = "sample_accession") - ) -``` - -```{r fig.height=11, fig.width=8.5} -comp_coag_df %>% - ggplot(aes( - x = condition, - y = ssgsea_score - )) + - geom_boxplot() + - facet_grid(strain ~ refinebio_specimen_part) + - labs(y = "KEGG Complement and Coagulation Cascades") + - theme_bw() + - # x-axis text at a 45 degree angle to increase readability - theme( - axis.text.x = element_text(angle = 45, hjust = 1), - text = element_text(size = 15) - ) -``` - -```{r} -# saving to file -ggsave(file.path( - plots_dir, - "GSE75574_ssgsea_comp_coag_facet.pdf" # Replace with relevant output plot name -), -plot = last_plot() + - theme(text = element_text(size = 10)) -) -``` - -Looks like there may be some differences between tissues in this pathway, with -some strains showing more pronounced differences in white adipose tissue in the -calorie-restricted vs. control comparison. -We should always follow up with more formal analysis (e.g., QuSAGE), but -this series of steps is a good way to explore one's data. - -#### Aside: Gene set size influences ssGSEA score values - -ssGSEA score values are not necessarily comparable between gene sets of -different sizes (number of genes). -If you are comparing ssGSEA scores between samples _within a gene set_, this is -not a concern. - -To demonstrate the effect of gene set size on scores, we'll perform a short -experiment with random gene sets. - -```{r} -# use all the gene symbols in the dataset as the pool of possible genes -all_genes <- symbol_exprs_df$SYMBOL - -# set a seed for reproducibility -set.seed(123) - -# GSVA::gsva takes gene sets as a list, so that's how we'll store the random -# gene sets -random_gene_sets <- list() - -# testing 5 different gene set sizes -for (pathway_size in c(25, 50, 100, 250, 500)) { - # generate 10 random sets of pathway_size - for (path_iter in 1:10) { - random_pathway_name <- paste("size", pathway_size, path_iter, sep = "_") - current_gene_set <- base::sample(x = all_genes, size = pathway_size) - random_gene_sets[[random_pathway_name]] <- current_gene_set - } -} - -# calculate ssGSEA scores for the random gene sets -random_ssgsea_results <- gsva( - expr = exprs_mat, - gset.idx.list = random_gene_sets, - method = "ssgsea", - verbose = FALSE -) - -# plot the results with ggplot2 -# first we need to get this in a form that is amenable for plotting, as gsva -# returns a matrix where columns are samples and rows are gene sets -random_long_df <- as.data.frame(random_ssgsea_results) %>% - # gene set names are rownames - tibble::rownames_to_column("gene_set") %>% - # long format - reshape2::melt(variable.name = "sample", value.name = "ssgsea_score") %>% - # extract the gene set size from the gene set name - dplyr::mutate(gene_set_size = stringr::word(gene_set, 2, sep = "_")) %>% - # we want to plot smallest no. genes -> largest no. genes - dplyr::mutate(gene_set_size = factor(gene_set_size, - levels = c(25, 50, 100, 250, 500) - )) - -# violin plot comparing no. genes / gene set size -random_long_df %>% - ggplot(aes(x = gene_set_size, y = ssgsea_score)) + - geom_violin() + - coord_flip() + - labs( - title = "Random gene set scores", - x = "gene set size", - y = "ssGSEA score" - ) + - theme_bw() -``` - -Note how a smaller gene set results in a larger range of scores. - -## Session info - -```{r} -sessioninfo::session_info() -``` diff --git a/Snakefile b/Snakefile index 7fe64d3f..0e38d621 100644 --- a/Snakefile +++ b/Snakefile @@ -8,8 +8,8 @@ rule target: "02-microarray/dimension-reduction_microarray_01_pca.html", "02-microarray/dimension-reduction_microarray_02_umap.html", "02-microarray/gene-id-annotation_microarray_01_ensembl.html", - "02-microarray/pathway-analysis_microarray_02_ora.html", - "02-microarray/pathway-analysis_microarray_03_gsea.html", + "02-microarray/pathway-analysis_microarray_01_ora.html", + "02-microarray/pathway-analysis_microarray_02_gsea.html", "02-microarray/ortholog-mapping_microarray_01_ensembl.html", "03-rnaseq/00-intro-to-rnaseq.html", "03-rnaseq/clustering_rnaseq_01_heatmap.html", diff --git a/components/_navbar.html b/components/_navbar.html index 811467dd..3201a3f2 100644 --- a/components/_navbar.html +++ b/components/_navbar.html @@ -7,7 +7,7 @@ - +

4.2 Import and set up data

Data downloaded from refine.bio include a metadata tab separated values (TSV) file and a data TSV file. This chunk of code will read the both TSV files and add them as data frames to your environment.

We stored our file paths as objects named metadata_file and data_file in this previous step.

-
# Read in metadata TSV file
-metadata <- readr::read_tsv(metadata_file)
+
# Read in metadata TSV file
+metadata <- readr::read_tsv(metadata_file)
## 
-## ── Column specification ──────────────────────────────────────────────────────────────────────────────────────
+## ── Column specification ───────────────────────────────────────────────────────────────────────────
 ## cols(
 ##   .default = col_character(),
 ##   refinebio_age = col_logical(),
@@ -4036,63 +4038,150 @@ 

4.2 Import and set up data

## refinebio_time = col_logical() ## ) ## ℹ Use `spec()` for the full column specifications.
-
# Read in data TSV file
-df <- readr::read_tsv(data_file) %>%
-  # Here we are going to store the gene IDs as rownames so that we can have a numeric matrix to perform calculations on later
-  tibble::column_to_rownames("Gene")
+
# Read in data TSV file
+df <- readr::read_tsv(data_file) %>%
+  # Here we are going to store the gene IDs as rownames so that we can have a numeric matrix to perform calculations on later
+  tibble::column_to_rownames("Gene")
## 
-## ── Column specification ──────────────────────────────────────────────────────────────────────────────────────
+## ── Column specification ───────────────────────────────────────────────────────────────────────────
 ## cols(
 ##   .default = col_double(),
 ##   Gene = col_character()
 ## )
 ## ℹ Use `spec()` for the full column specifications.

Let’s ensure that the metadata and data are in the same sample order.

-
# Make the data in the order of the metadata
-df <- df %>%
-  dplyr::select(metadata$refinebio_accession_code)
-
-# Check if this is in the same order
-all.equal(colnames(df), metadata$refinebio_accession_code)
+
# Make the data in the order of the metadata
+df <- df %>%
+  dplyr::select(metadata$refinebio_accession_code)
+
+# Check if this is in the same order
+all.equal(colnames(df), metadata$refinebio_accession_code)
## [1] TRUE

4.2.1 Prepare data for DESeq2

There are two things we neeed to do to prep our expression data for DESeq2.

First, we need to make sure all of the values in our data are converted to integers as required by a DESeq2 function we will use later.

Then, we need to filter out the genes that have not been expressed or that have low expression counts. This is recommended by WGCNA docs for RNA-seq data. Removing low count genes can also help improve your WGCNA results. We are going to do some pre-filtering to keep only genes with 50 or more reads in total across the samples.

-
# The next DESeq2 functions need the values to be converted to integers
-df <- round(df) %>%
-  # The next steps require a data frame and round() returns a matrix
-  as.data.frame() %>%
-  # Only keep rows that have total counts above the cutoff
-  dplyr::filter(rowSums(.) >= 50)
+
# The next DESeq2 functions need the values to be converted to integers
+df <- round(df) %>%
+  # The next steps require a data frame and round() returns a matrix
+  as.data.frame() %>%
+  # Only keep rows that have total counts above the cutoff
+  dplyr::filter(rowSums(.) >= 50)

4.3 Create a DESeqDataset

We will be using the DESeq2 package for normalizing and transforming our data, which requires us to format our data into a DESeqDataSet object. We turn the data frame (or matrix) into a DESeqDataSet object and specify which variable labels our experimental groups using the design argument (Love et al. 2014). In this chunk of code, we will not provide a specific model to the design argument because we are not performing a differential expression analysis.

-
# Create a `DESeqDataSet` object
-dds <- DESeqDataSetFromMatrix(
-  countData = df, # Our prepped data frame with counts
-  colData = metadata, # Data frame with annotation for our samples
-  design = ~1 # Here we are not specifying a model
-)
+
# Create a `DESeqDataSet` object
+dds <- DESeqDataSetFromMatrix(
+  countData = df, # Our prepped data frame with counts
+  colData = metadata, # Data frame with annotation for our samples
+  design = ~1 # Here we are not specifying a model
+)
## converting counts to integer mode

4.4 Perform DESeq2 normalization and transformation

We often suggest normalizing and transforming your data for various applications and in this instance WGCNA’s authors suggest using variance stabilizing transformation before running WGCNA.
We are going to use the vst() function from the DESeq2 package to normalize and transform the data. For more information about these transformation methods, see here.

-
# Normalize and transform the data in the `DESeqDataSet` object using the `vst()`
-# function from the `DESEq2` R package
-dds_norm <- vst(dds)
+
# Normalize and transform the data in the `DESeqDataSet` object using the `vst()`
+# function from the `DESEq2` R package
+dds_norm <- vst(dds)

4.5 Format normalized data for WGCNA

Extract the normalized counts to a matrix and transpose it so we can pass it to WGCNA.

-
# Retrieve the normalized data from the `DESeqDataSet`
-normalized_counts <- assay(dds_norm) %>%
-  t() # Transpose this data
+
# Retrieve the normalized data from the `DESeqDataSet`
+normalized_counts <- assay(dds_norm) %>%
+  t() # Transpose this data
+
+
+

4.6 Determine parameters for WGCNA

+

To identify which genes are in the same modules, WGCNA first creates a weighted network to define which genes are near each other. The measure of “adjacency” it uses is based on the correlation matrix, but requires the definition of a threshold value, which in turn depends on a “power” parameter that defines the exponent used when transforming the correlation values. The choice of power parameter will affect the number of modules identified, and the WGCNA modules provides the pickSoftThreshold() function to help identify good choices for this parameter.

+
sft <- pickSoftThreshold(normalized_counts,
+  dataIsExpr = TRUE,
+  corFnc = cor,
+  networkType = "signed"
+)
+
## Warning: executing %dopar% sequentially: no parallel backend registered
+
##    Power SFT.R.sq  slope truncated.R.sq mean.k. median.k. max.k.
+## 1      1  0.58200 12.200          0.957 13500.0   13600.0  15500
+## 2      2  0.44500  5.130          0.972  7630.0    7650.0   9910
+## 3      3  0.26300  2.570          0.985  4480.0    4450.0   6680
+## 4      4  0.06480  0.914          0.985  2730.0    2680.0   4720
+## 5      5  0.00662 -0.236          0.964  1720.0    1660.0   3450
+## 6      6  0.15900 -1.010          0.965  1120.0    1060.0   2580
+## 7      7  0.36500 -1.470          0.971   746.0     689.0   1980
+## 8      8  0.50000 -1.730          0.972   509.0     459.0   1550
+## 9      9  0.59700 -1.910          0.972   356.0     313.0   1220
+## 10    10  0.67000 -2.060          0.973   253.0     217.0    982
+## 11    12  0.74000 -2.260          0.970   135.0     110.0    651
+## 12    14  0.79400 -2.320          0.978    76.9      58.6    447
+## 13    16  0.82000 -2.350          0.981    45.9      32.7    315
+## 14    18  0.83800 -2.360          0.985    28.6      18.9    227
+## 15    20  0.84500 -2.350          0.987    18.5      11.2    167
+

This sft object has a lot of information, we will want to plot some of it to figure out what our power soft-threshold should be. We have to first calculate a measure of the model fit, the signed \(R^2\), and make that a new variable.

+
sft_df <- data.frame(sft$fitIndices) %>%
+  dplyr::mutate(model_fit = -sign(slope) * SFT.R.sq)
+

Now, let’s plot the model fitting by the power soft threshold so we can decide on a soft-threshold for power.

+
ggplot(sft_df, aes(x = Power, y = model_fit, label = Power)) +
+  # Plot the points
+  geom_point() +
+  # We'll put the Power labels slightly above the data points
+  geom_label(nudge_y = 0.1) +
+  # We will plot what WGCNA recommends as an R^2 cutoff
+  geom_hline(yintercept = 0.80, col = "red") +
+  # Just in case our values are low, we want to make sure we can still see the 0.80 level
+  ylim(c(min(sft_df$model_fit), 1)) +
+  # We can add more sensible labels for our axis
+  xlab("Soft Threshold (power)") +
+  ylab("Scale Free Topology Model Fit, signed R^2") +
+  ggtitle("Scale independence") +
+  # This adds some nicer aesthetics to our plot
+  theme_classic()
+

+

Using this plot we can decide on a power parameter. WGCNA’s authors recommend using a power that has an signed \(R^2\) above 0.80, otherwise they warn your results may be too noisy to be meaningful.

+

If you have multiple power values with signed \(R^2\) above 0.80, then picking the one at an inflection point, in other words where the \(R^2\) values seem to have reached their saturation (Zhang and Horvath 2005). You want to a power that gives you a big enough \(R^2\) but is not excessively large.

+

So using the plot above, going with a power soft-threshold of 16!

+

If you find you have all very low \(R^2\) values this may be because there are too many genes with low values that are cluttering up the calculations. You can try returning to gene filtering step and choosing a more stringent cutoff (you’ll then need to re-run the transformation and subsequent steps to remake this plot to see if that helped).

+
sft_df %>%
+  ggplot() +
+  geom_label(aes(x = Power, y = max.k.), label = sft_df$Power) +
+  # We can add more sensible labels for our axis
+  xlab("Soft Threshold (power)") +
+  ylab("Scale Free Topology Model Fit, signed R^2") +
+  ggtitle("Scale independence") +
+  # This adds some nicer aesthetics to our plot
+  theme_classic()
+

+
+
+

4.7 Run WGCNA!

+

We will use the blockwiseModules() function to find gene co-expression modules in WGCNA, using 16 for the power argument like we determined above.

+

This next step takes some time to run. The blockwise part of the blockwiseModules() function name refers to that these calculations will be done on chunks of your data at a time to help with conserving computing resources.

+

Here we are using the default maxBlockSize, 5000 but, you may want to adjust the maxBlockSize argument depending on your computer’s memory. The authors of WGCNA recommend running the largest block your computer can handle and they provide some approximations as to GB of memory of a laptop and what maxBlockSize it should be able to handle:

+
+

• If the reader has access to a large workstation with more than 4 GB of memory, the parameter maxBlockSize can be increased. A 16GB workstation should handle up to 20000 probes; a 32GB workstation should handle perhaps 30000. A 4GB standard desktop or a laptop may handle up to 8000-10000 probes, depending on operating system and other running programs.

+
+

(Langfelder and Horvath 2016)

+
bwnet <- blockwiseModules(normalized_counts,
+  maxBlockSize = 5000, # What size chunks (how many genes) the calculations should be run in
+  TOMType = "signed", # topological overlap matrix
+  power = 16, # soft threshold for network construction
+  numericLabels = TRUE, # Let's use numbers instead of colors for module labels
+  randomSeed = 1234, # there's some randomness associated with this calculation
+  # so we should set a seed
+)
+

The TOMtype argument specifies what kind of topological overlap matrix (TOM) should be used to make gene modules. You can safely assume for most situations a signed network represents what you want – we want WGCNA to pay attention to directionality. However if you suspect you may benefit from an unsigned network, where positive/negative is ignored see this article to help you figure that out (Langfelder 2018).

+

There are a lot of other settings you can tweak – look at ?blockwiseModules help page as well as the WGCNA tutorial (Langfelder and Horvath 2016).

+
+
+

4.8 Write main WGCNA results object to file

+

We will save our whole results object to an RDS file in case we want to return to our original WGCNA results.

+
readr::write_rds(bwnet,
+  file = file.path("results", "SRP133573_wgcna_results.RDS")
+)

Next sections addressed in upcoming PR

@@ -4107,8 +4196,8 @@

5 Resources for further learning<

6 Session info

At the end of every analysis, before saving your notebook, we recommend printing out your session info. This helps make your code more reproducible by recording what versions of software and packages you used to run this.

-
# Print session info
-sessionInfo()
+
# Print session info
+sessionInfo()
## R version 4.0.2 (2020-06-22)
 ## Platform: x86_64-pc-linux-gnu (64-bit)
 ## Running under: Ubuntu 20.04 LTS
@@ -4129,48 +4218,49 @@ 

6 Session info

## [8] methods base ## ## other attached packages: -## [1] WGCNA_1.69 fastcluster_1.1.25 -## [3] dynamicTreeCut_1.63-1 magrittr_1.5 -## [5] DESeq2_1.30.0 SummarizedExperiment_1.20.0 -## [7] Biobase_2.50.0 MatrixGenerics_1.2.0 -## [9] matrixStats_0.57.0 GenomicRanges_1.42.0 -## [11] GenomeInfoDb_1.26.0 IRanges_2.24.0 -## [13] S4Vectors_0.28.0 BiocGenerics_0.36.0 -## [15] optparse_1.6.6 +## [1] ggplot2_3.3.2 WGCNA_1.69 +## [3] fastcluster_1.1.25 dynamicTreeCut_1.63-1 +## [5] magrittr_1.5 DESeq2_1.30.0 +## [7] SummarizedExperiment_1.20.0 Biobase_2.50.0 +## [9] MatrixGenerics_1.2.0 matrixStats_0.57.0 +## [11] GenomicRanges_1.42.0 GenomeInfoDb_1.26.0 +## [13] IRanges_2.24.0 S4Vectors_0.28.0 +## [15] BiocGenerics_0.36.0 optparse_1.6.6 ## ## loaded via a namespace (and not attached): -## [1] bitops_1.0-6 bit64_4.0.5 doParallel_1.0.15 -## [4] RColorBrewer_1.1-2 httr_1.4.2 R.cache_0.14.0 -## [7] tools_4.0.2 backports_1.1.10 R6_2.4.1 -## [10] rpart_4.1-15 Hmisc_4.4-1 DBI_1.1.0 -## [13] colorspace_1.4-1 nnet_7.3-14 gridExtra_2.3 -## [16] tidyselect_1.1.0 preprocessCore_1.52.0 bit_4.0.4 -## [19] compiler_4.0.2 cli_2.1.0 htmlTable_2.1.0 -## [22] DelayedArray_0.16.0 checkmate_2.0.0 scales_1.1.1 -## [25] readr_1.4.0 genefilter_1.72.0 stringr_1.4.0 -## [28] digest_0.6.25 foreign_0.8-80 rmarkdown_2.4 -## [31] R.utils_2.10.1 XVector_0.30.0 jpeg_0.1-8.1 -## [34] base64enc_0.1-3 pkgconfig_2.0.3 htmltools_0.5.0 -## [37] styler_1.3.2 htmlwidgets_1.5.2 rlang_0.4.8 -## [40] impute_1.64.0 rstudioapi_0.11 RSQLite_2.2.1 -## [43] generics_0.0.2 BiocParallel_1.24.1 dplyr_1.0.2 -## [46] R.oo_1.24.0 RCurl_1.98-1.2 Formula_1.2-3 -## [49] GO.db_3.12.1 GenomeInfoDbData_1.2.4 Matrix_1.2-18 -## [52] Rcpp_1.0.5 munsell_0.5.0 fansi_0.4.1 -## [55] lifecycle_0.2.0 R.methodsS3_1.8.1 stringi_1.5.3 -## [58] yaml_2.2.1 zlibbioc_1.36.0 grid_4.0.2 -## [61] blob_1.2.1 crayon_1.3.4 lattice_0.20-41 -## [64] splines_4.0.2 annotate_1.68.0 hms_0.5.3 -## [67] locfit_1.5-9.4 ps_1.4.0 knitr_1.30 -## [70] pillar_1.4.6 geneplotter_1.68.0 codetools_0.2-16 -## [73] XML_3.99-0.5 glue_1.4.2 evaluate_0.14 -## [76] latticeExtra_0.6-29 data.table_1.13.0 png_0.1-7 -## [79] vctrs_0.3.4 foreach_1.5.0 gtable_0.3.0 -## [82] getopt_1.20.3 purrr_0.3.4 rematch2_2.1.2 -## [85] assertthat_0.2.1 ggplot2_3.3.2 xfun_0.18 -## [88] xtable_1.8-4 survival_3.1-12 tibble_3.0.4 -## [91] iterators_1.0.12 AnnotationDbi_1.52.0 memoise_1.1.0 -## [94] cluster_2.1.0 ellipsis_0.3.1
+## [1] colorspace_1.4-1 ellipsis_0.3.1 htmlTable_2.1.0 +## [4] XVector_0.30.0 base64enc_0.1-3 rstudioapi_0.11 +## [7] farver_2.0.3 getopt_1.20.3 bit64_4.0.5 +## [10] AnnotationDbi_1.52.0 fansi_0.4.1 codetools_0.2-16 +## [13] splines_4.0.2 R.methodsS3_1.8.1 doParallel_1.0.15 +## [16] impute_1.64.0 geneplotter_1.68.0 knitr_1.30 +## [19] Formula_1.2-3 annotate_1.68.0 cluster_2.1.0 +## [22] GO.db_3.12.1 png_0.1-7 R.oo_1.24.0 +## [25] readr_1.4.0 compiler_4.0.2 httr_1.4.2 +## [28] backports_1.1.10 assertthat_0.2.1 Matrix_1.2-18 +## [31] cli_2.1.0 htmltools_0.5.0 tools_4.0.2 +## [34] gtable_0.3.0 glue_1.4.2 GenomeInfoDbData_1.2.4 +## [37] dplyr_1.0.2 Rcpp_1.0.5 styler_1.3.2 +## [40] vctrs_0.3.4 preprocessCore_1.52.0 iterators_1.0.12 +## [43] xfun_0.18 stringr_1.4.0 ps_1.4.0 +## [46] lifecycle_0.2.0 XML_3.99-0.5 zlibbioc_1.36.0 +## [49] scales_1.1.1 hms_0.5.3 rematch2_2.1.2 +## [52] RColorBrewer_1.1-2 yaml_2.2.1 memoise_1.1.0 +## [55] gridExtra_2.3 rpart_4.1-15 latticeExtra_0.6-29 +## [58] stringi_1.5.3 RSQLite_2.2.1 genefilter_1.72.0 +## [61] foreach_1.5.0 checkmate_2.0.0 BiocParallel_1.24.1 +## [64] rlang_0.4.8 pkgconfig_2.0.3 bitops_1.0-6 +## [67] evaluate_0.14 lattice_0.20-41 purrr_0.3.4 +## [70] htmlwidgets_1.5.2 labeling_0.3 bit_4.0.4 +## [73] tidyselect_1.1.0 R6_2.4.1 generics_0.0.2 +## [76] Hmisc_4.4-1 DelayedArray_0.16.0 DBI_1.1.0 +## [79] pillar_1.4.6 foreign_0.8-80 withr_2.3.0 +## [82] survival_3.1-12 RCurl_1.98-1.2 nnet_7.3-14 +## [85] tibble_3.0.4 crayon_1.3.4 rmarkdown_2.4 +## [88] jpeg_0.1-8.1 locfit_1.5-9.4 grid_4.0.2 +## [91] data.table_1.13.0 blob_1.2.1 digest_0.6.25 +## [94] xtable_1.8-4 R.cache_0.14.0 R.utils_2.10.1 +## [97] munsell_0.5.0

References

@@ -4187,9 +4277,15 @@

References

Langfelder P., and S. Horvath, 2016 Tutorials for the WGCNA package. https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/Tutorials/

+
+

Langfelder P., 2018 Signed or unsigned: Which network type is preferable? https://peterlangfelder.com/2018/11/25/signed-or-unsigned-which-network-type-is-preferable/

+

Love M. I., W. Huber, and S. Anders, 2014 Moderated estimation of fold change and dispersion for RNA-Seq data with DESeq2. Genome Biology 15. https://doi.org/10.1186/s13059-014-0550-8

+
+

Zhang B., and S. Horvath, 2005 A general framework for weighted gene co-expression network analysis. Statistical Applications in Genetics and Molecular Biology 4. https://doi.org/10.2202/1544-6115.1128

+
diff --git a/components/references.bib b/components/references.bib index 96b04d23..e68ead75 100644 --- a/components/references.bib +++ b/components/references.bib @@ -552,6 +552,14 @@ @website{pca-visually-explained url = {https://setosa.io/ev/principal-component-analysis/} } +@manual{Pedersen2020, + title = {ggforce: Accelerating 'ggplot2'}, + author = {Thomas Lin Pedersen}, + year = {2020}, + url = {https://ggforce.data-imaginist.com}, + github = {https://github.com/thomasp85/ggforce}, + } + @article{Pepke2009, author = {Pepke, S. and Wold, B. and Mortazavi, A. }, title = {Computation for {ChIP-seq} and {RNA-seq} studies}, From 114d6fe9612f401090cfef98c292f5109bdeb1aa Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Fri, 20 Nov 2020 12:24:35 -0500 Subject: [PATCH 41/50] Add pathway analysis intro paragraph to microarray ORA (#356) * Try out intro and fix filenames * Undo intro paragraph for now. Too much * Add intro paragraph * Fix typo, add links * Incorporate cbethell review * Wording change from @envest --- .../pathway-analysis_microarray_01_ora.Rmd | 103 +++++++++++------- .../pathway-analysis_microarray_01_ora.html | 56 +++++++++- 2 files changed, 114 insertions(+), 45 deletions(-) diff --git a/02-microarray/pathway-analysis_microarray_01_ora.Rmd b/02-microarray/pathway-analysis_microarray_01_ora.Rmd index 74e8b73a..92e13652 100644 --- a/02-microarray/pathway-analysis_microarray_01_ora.Rmd +++ b/02-microarray/pathway-analysis_microarray_01_ora.Rmd @@ -11,34 +11,53 @@ output: # Purpose of this analysis -This example is one of pathway analysis module set, we recommend looking at the [pathway analysis introduction](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_00_intro.html) to help you determine which pathway analysis method is best suited for your purposes. +This example is one of pathway analysis module set, we recommend looking at the [pathway analysis table below](#how-to-choose-a-pathway-analysis) to help you determine which pathway analysis method is best suited for your purposes. This particular example analysis shows how you can use over-representation analysis (ORA) to determine if a set of genes (e.g., those differentially expressed using some cutoff) shares more or fewer genes with gene sets/pathways than we would expect at random. This pathway analysis method does not require any particular sample size, since the only input from your dataset is a set of genes of interest [@Yaari2013]. ⬇️ [**Jump to the analysis code**](#analysis) ⬇️ +### What is pathway analysis? + +Pathway analysis refers to any one of many techniques that uses predetermined sets of genes that are related or coordinated in their expression in some way (e.g., participate in the same molecular process, are regulated by the same transcription factor) to interpret a high-throughput experiment. +In the context of [refine.bio](https://www.refine.bio/), we use these techniques to analyze and interpret genome-wide gene expression experiments. +The rationale for performing pathway analysis is that looking at the pathway-level may be more biologically meaningful than considering individual genes, especially if a large number of genes are differentially expressed between conditions of interest. +In addition, many relatively small changes in the expression values of genes in the same pathway could lead to a phenotypic outcome and these small changes may go undetected in differential gene expression analysis. + +We highly recommend taking a look at [Ten Years of Pathway Analysis: Current Approaches and Outstanding Challenges](https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1002375) from @Khatri2012 for a more comprehensive overview. We have provided primary publications and documentation of the methods we will introduce below as well as some recommended reading in the [`Resources for further learning` section](#resources-for-further-learning). + +### How to choose a pathway analysis? + +This table summarizes the pathway analyses examples in this module. + +|Analysis|What is required for input|What output looks like |✅ Pros| ⚠️ Cons| +|--------|--------------------------|-----------------------|-------|-------| +|[**ORA (Over-representation Analysis)**](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_01_ora.html)|A list of gene IDs (no stats needed)|A per-pathway hypergeometric test result|- Simple

- Inexpensive computationally to calculate p-values| - Requires arbitrary thresholds and ignores any statistics associated with a gene

- Assumes independence of genes and pathways| +|[**GSEA (Gene Set Enrichment Analysis)**](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_02_gsea.html)|A list of genes IDs with gene-level summary statistics|A per-pathway enrichment score|- Includes all genes (no arbitrary threshold!)

- Attempts to measure coordination of genes|- Permutations can be expensive

- Does not account for pathway overlap

- Two-group comparisons not always appropriate/feasible| +|[**GSVA (Gene Set Variation Analysis)**](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_03_gsva.html)|A gene expression matrix (like what you get from refine.bio directly)|Pathway-level scores on a per-sample basis|- Does not require two groups to compare upfront

- Normally distributed scores|- Scores are not a good fit for gene sets that contain genes that go up AND down

- Method doesn’t assign statistical significance itself

- Recommended sample size n > 10| + # How to run this example For general information about our tutorials and the basic software packages you will need, please see our ['Getting Started' section](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-this-tutorial-is-structured). -We recommend taking a look at our [Resources for Learning R](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#resources-for-learning-r) if you have not written code in R before. +We recommend taking a look at our [Resources for Learning R](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#resources-for-learning-r) if you have not written code in R before. ## Obtain the `.Rmd` file -To run this example yourself, [download the `.Rmd` for this analysis by clicking this link](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_02_ora_with_webgestaltr.Rmd). +To run this example yourself, [download the `.Rmd` for this analysis by clicking this link](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_01_ora.Rmd). -Clicking this link will most likely send this to your downloads folder on your computer. +Clicking this link will most likely send this to your downloads folder on your computer. Move this `.Rmd` file to where you would like this example and its files to be stored. You can open this `.Rmd` file in RStudio and follow the rest of these steps from there. (See our [section about getting started with R notebooks](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-and-use-rmds) if you are unfamiliar with `.Rmd` files.) -## Set up your analysis folders +## Set up your analysis folders Good file organization is helpful for keeping your data analysis project on track! -We have set up some code that will automatically set up a folder structure for you. -Run this next chunk to set up your folders! +We have set up some code that will automatically set up a folder structure for you. +Run this next chunk to set up your folders! -If you have trouble running this chunk, see our [introduction to using `.Rmd`s](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-and-use-rmds) for more resources and explanations. +If you have trouble running this chunk, see our [introduction to using `.Rmd`s](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-and-use-rmds) for more resources and explanations. ```{r} # Create the data folder if it doesn't exist @@ -79,22 +98,22 @@ For this example analysis, we will use this [CREB overexpression zebrafish exper ## Check out our file structure! -Your new analysis folder should contain: +Your new analysis folder should contain: - The example analysis `.Rmd` you downloaded -- A folder called `data` (currently empty) +- A folder called `data` (currently empty) - A folder for `plots` (currently empty) - A folder for `results` (currently empty) - + Your example analysis folder should contain your `.Rmd` and three empty folders (which won't be empty for long!). -If the concept of a "file path" is unfamiliar to you; we recommend taking a look at our [section about file paths](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#an-important-note-about-file-paths-and-Rmds). +If the concept of a "file path" is unfamiliar to you; we recommend taking a look at our [section about file paths](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#an-important-note-about-file-paths-and-Rmds). # Using a different refine.bio dataset with this analysis? If you'd like to adapt an example analysis to use a different dataset from [refine.bio](https://www.refine.bio/), we recommend placing the files in the `data/` directory you created and changing the filenames and paths in the notebook to match these files (we've put comments to signify where you would need to change the code). We suggest saving plots and results to `plots/` and `results/` directories, respectively, as these are automatically created by the notebook. -From here you can customize this analysis example to fit your own scientific questions and preferences. +From here you can customize this analysis example to fit your own scientific questions and preferences. *** @@ -149,7 +168,7 @@ library(org.Dr.eg.db) library(magrittr) ``` -## Import data +## Import data We will read in the differential expression results we will download from online. These results are from a zebrafish microarray experiment we used for [differential expression analysis for two groups](https://alexslemonade.github.io/refinebio-examples/02-microarray/differential-expression_microarray_02_2-groups.html) using [`limma`](https://bioconductor.org/packages/release/bioc/html/limma.html) [@Ritchie2015]. @@ -157,14 +176,14 @@ The table contains Ensembl gene IDs, log fold-changes for each group, and adjust We can identify differentially regulated genes by filtering these results and use this list as input to ORA. Instead of using the URL below, you can use a file path to a TSV file with your desired gene list results. -First we will assign the URL to its own variable called, `dge_url`. +First we will assign the URL to its own variable called, `dge_url`. ```{r} # Define the url to your differential expression results file dge_url <- "https://refinebio-examples.s3.us-east-2.amazonaws.com/02-microarray/results/GSE71270/GSE71270_limma_results.tsv" ``` -Read in the file that has differential expression results. +Read in the file that has differential expression results. Here we are using the URL we set up above, but this can be a local file path instead _i.e._ you can replace `dge_url` in the code below with a path to file you have on your computer like: `file.path("results", "GSE71270_limma_results.tsv")`. ```{r} @@ -174,8 +193,8 @@ Here we are using the URL we set up above, but this can be a local file path ins dge_df <- readr::read_tsv(dge_url) ``` -`read_tsv()` can read TSV files online and doesn't necessarily require you download the file first. -Let's take a look at what these contrast results from the differential expression analysis look like. +`read_tsv()` can read TSV files online and doesn't necessarily require you download the file first. +Let's take a look at what these contrast results from the differential expression analysis look like. ```{r} dge_df @@ -208,15 +227,15 @@ MSigDB contains [8 different gene set collections](https://www.gsea-msigdb.org/g In this example, we will use pathways that are gene sets considered to be "canonical representations of a biological process compiled by domain experts" and are a subset of `C2: curated gene sets` [@Subramanian2005]. -Specifically, we will use the [KEGG (Kyoto Encyclopedia of Genes and Genomes)](https://www.genome.jp/kegg/) pathways [@Kanehisa2000]. +Specifically, we will use the [KEGG (Kyoto Encyclopedia of Genes and Genomes)](https://www.genome.jp/kegg/) pathways [@Kanehisa2000]. -First, let's take a look at what information is included in this data frame. +First, let's take a look at what information is included in this data frame. ```{r} head(dr_msigdb_df) ``` -We will need to use `gs_cat` and `gs_subcat` columns to construct a filter step that will only keep curated gene sets and KEGG pathways. +We will need to use `gs_cat` and `gs_subcat` columns to construct a filter step that will only keep curated gene sets and KEGG pathways. ```{r} # Filter the zebrafish data frame to the KEGG pathways that are included in the @@ -234,7 +253,7 @@ The `clusterProfiler()` function we will use requires a data frame with two colu Our data frame with KEGG terms contains Entrez IDs and gene symbols. -In our differential expression results data frame, `dge_df` we have Ensembl gene identifiers. +In our differential expression results data frame, `dge_df` we have Ensembl gene identifiers. So we will need to convert our Ensembl IDs into either gene symbols or Entrez IDs. ## Gene identifier conversion @@ -291,13 +310,13 @@ gene_key_df <- data.frame( dplyr::filter(!is.na(gene_symbol)) ``` -Let's see a preview of `gene_key_df`. +Let's see a preview of `gene_key_df`. ```{r} head(gene_key_df) ``` -Now we are ready to add the `gene_key_df` to our data frame with the differential expression stats, `dge_df`. +Now we are ready to add the `gene_key_df` to our data frame with the differential expression stats, `dge_df`. Here we're using a `dplyr::left_join()` because we only want to retain the genes that have gene symbols and this will filter out anything in our `dge_df` that does not have gene symbols when we join using the Ensembl gene identifiers. ```{r} @@ -311,7 +330,7 @@ dge_annot_df <- gene_key_df %>% ) ``` -Let's take a look at what this data frame looks like. +Let's take a look at what this data frame looks like. ```{r} # Print out a preview @@ -326,15 +345,15 @@ Over-representation testing using `clusterProfiler` is based on a hypergeometric Where `N` is the number of genes in the background distribution, `M` is the number of genes in a pathway, `n` is the number of genes we are interested in (our differentially expressed genes), and `k` is the number of genes that overlap between the pathway and our genes of interest. -So, we will need to provide to `clusterProfiler` two genes lists: +So, we will need to provide to `clusterProfiler` two genes lists: -1) Our genes of interest (`n`) -2) What genes were in our total background set (`N`). (All genes that originally had an opportunity to be measured). +1) Our genes of interest (`n`) +2) What genes were in our total background set (`N`). (All genes that originally had an opportunity to be measured). ## Determine our genes of interest list -We will use our differential expression results to get a genes of interest list. -Let's use our adjusted p values as a cutoff. +We will use our differential expression results to get a genes of interest list. +Let's use our adjusted p values as a cutoff. ```{r} # Select genes that are below a cutoff @@ -349,7 +368,7 @@ There are a lot of ways we could make a genes of interest list, and using a p-va ORA generally requires you make some sort of arbitrary decision to obtain your genes of interest list and this is one of the approach's weaknesses -- to get to a gene list we've removed all other context. -Because one `gene_symbol` may map to multiple Ensembl IDs, we need to make sure we have no repeated gene symbols in this list. +Because one `gene_symbol` may map to multiple Ensembl IDs, we need to make sure we have no repeated gene symbols in this list. ```{r} # Reduce to only unique gene symbols @@ -361,7 +380,7 @@ head(genes_of_interest) ## Determine our background set gene list -Sometimes folks consider genes from the entire genome to comprise the background, but for our microarray data, we should consider all genes that were measured as our background set. +Sometimes folks consider genes from the entire genome to comprise the background, but for our microarray data, we should consider all genes that were measured as our background set. In other words, if we are unable to detect a gene, it should not be in our background set. We can obtain our detected genes list from our data frame, `dge_annot_df` (which we haven't done filtering on). @@ -392,8 +411,8 @@ kegg_ora_results <- enricher( *Note: using `enrichKEGG()` is a shortcut for doing ORA using KEGG, but the approach we covered here can be used with any gene sets you'd like!* -What is returned by `enricher()`? -You can run `View(kegg_ora_results)` or click on the object in your Environment panel. +What is returned by `enricher()`? +You can run `View(kegg_ora_results)` or click on the object in your Environment panel. The information we're most likely interested in is in the `results` slot. Let's convert this into a data frame that we can write to file. @@ -402,19 +421,19 @@ Let's convert this into a data frame that we can write to file. kegg_result_df <- data.frame(kegg_ora_results@result) ``` -Let's print out a sneak peek of it here and take a look at how many sets do we have that fit our cutoff of `0.1` FDR? +Let's print out a sneak peek of it here and take a look at how many sets do we have that fit our cutoff of `0.1` FDR? ```{r} kegg_result_df %>% dplyr::filter(p.adjust < 0.1) ``` -Looks like there are four KEGG sets returned as significant at FDR of `0.1`. +Looks like there are four KEGG sets returned as significant at FDR of `0.1`. ## Visualizing results We can use a dot plot to visualize our significant enrichment results. -The `enrichplot::dotplot()` function will only plot gene sets that are significant according to the multiple testing corrected p values (in the `p.adjust` column) and the `pvalueCutoff` you provided in the [`enricher()` step](#run-ora-using-the-enricher-function). +The `enrichplot::dotplot()` function will only plot gene sets that are significant according to the multiple testing corrected p values (in the `p.adjust` column) and the `pvalueCutoff` you provided in the [`enricher()` step](#run-ora-using-the-enricher-function). ```{r} enrich_plot <- enrichplot::dotplot(kegg_ora_results) @@ -427,7 +446,7 @@ Use `?enrichplot::dotplot` to see the help page for more about how to use this f This plot is arguably more useful when we have a large number of significant pathways. -Let's save it to a PNG. +Let's save it to a PNG. ```{r} ggplot2::ggsave(file.path(plots_dir, "GSE71270_ora_enrich_plot.png"), @@ -441,10 +460,10 @@ We can use an [UpSet plot](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC4720993/ enrichplot::upsetplot(kegg_ora_results) ``` -See that `KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION` and `KEGG_LYSOSOME` have all their genes in common. +See that `KEGG_ANTIGEN_PROCESSING_AND_PRESENTATION` and `KEGG_LYSOSOME` have all their genes in common. Gene sets or pathways aren't independent! -Let's also save this to a PNG. +Let's also save this to a PNG. ```{r} ggplot2::ggsave(file.path(plots_dir, "GSE71270_ora_upset_plot.png"), @@ -472,8 +491,8 @@ readr::write_tsv( # Session info -At the end of every analysis, before saving your notebook, we recommend printing out your session info. -This helps make your code more reproducible by recording what versions of software and packages you used to run this. +At the end of every analysis, before saving your notebook, we recommend printing out your session info. +This helps make your code more reproducible by recording what versions of software and packages you used to run this. ```{r} # Print session info diff --git a/02-microarray/pathway-analysis_microarray_01_ora.html b/02-microarray/pathway-analysis_microarray_01_ora.html index 63dd55b4..5306c515 100644 --- a/02-microarray/pathway-analysis_microarray_01_ora.html +++ b/02-microarray/pathway-analysis_microarray_01_ora.html @@ -3771,16 +3771,66 @@

November 2020

1 Purpose of this analysis

-

This example is one of pathway analysis module set, we recommend looking at the pathway analysis introduction to help you determine which pathway analysis method is best suited for your purposes.

+

This example is one of pathway analysis module set, we recommend looking at the pathway analysis table below to help you determine which pathway analysis method is best suited for your purposes.

This particular example analysis shows how you can use over-representation analysis (ORA) to determine if a set of genes (e.g., those differentially expressed using some cutoff) shares more or fewer genes with gene sets/pathways than we would expect at random. This pathway analysis method does not require any particular sample size, since the only input from your dataset is a set of genes of interest (Yaari et al. 2013).

⬇️ Jump to the analysis code ⬇️

+
+

1.0.1 What is pathway analysis?

+

We refer to any technique that uses predetermined sets of genes that are related or coordinated in their expression in some way (e.g., participate in the same molecular process, are regulated by the same transcription factor) to interpret a high-throughput experiment as pathway analysis. In the context of refine.bio, we use these techniques to analyze and interpret genome-wide gene expression experiments. The rationale for performing pathway analysis is that looking at the pathway-level may be more biologically meaningful than considering individual genes, especially if a large number of genes are differentially expressed between conditions of interest. In addition, many relatively small changes in the expression values of genes in the same pathway could lead to a phenotypic outcome and these small changes may go undetected in differential gene expression analysis.

+

We highly recommend taking a look at Ten Years of Pathway Analysis: Current Approaches and Outstanding Challenges from Khatri et al. (2012) for a more comprehensive overview. We have provided primary publications and documentation of the methods we will introduce below as well as some recommended reading in the Resources for further learning section.

+
+
+

1.0.2 How to choose a pathway analysis?

+

This table summarizes the pathway analyses examples in this module.

+ +++++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AnalysisWhat is required for inputWhat output looks like✅ Pros⚠️ Cons
ORA (Over-representation Analysis)A list of gene IDs (no stats needed)A per-pathway hypergeometric test result- Simple

- Inexpensive computationally to calculate p-values
- Requires arbitrary thresholds and ignores any statistics associated with a gene

- Assumes independence of genes and pathways
GSEA (Gene Set Enrichment Analysis)A list of genes IDs with gene-level summary statisticsA per-pathway enrichment score- Includes all genes (no arbitrary threshold!)

- Attempts to measure coordination of genes
- Permutations can be expensive

- Does not account for pathway overlap

- Two-group comparisons not always appropriate/feasible
GSVA (Gene Set Variation Analysis)A gene expression matrix (like what you get from refine.bio directly)Pathway-level scores on a per-sample basis- Does not require two groups to compare upfront

- Normally distributed scores
- Scores are not a good fit for gene sets that contain genes that go up AND down

- Method doesn’t assign statistical significance itself

- Recommended sample size n > 10
+

2 How to run this example

For general information about our tutorials and the basic software packages you will need, please see our ‘Getting Started’ section. We recommend taking a look at our Resources for Learning R if you have not written code in R before.

2.1 Obtain the .Rmd file

-

To run this example yourself, download the .Rmd for this analysis by clicking this link.

+

To run this example yourself, download the .Rmd for this analysis by clicking this link.

Clicking this link will most likely send this to your downloads folder on your computer. Move this .Rmd file to where you would like this example and its files to be stored.

You can open this .Rmd file in RStudio and follow the rest of these steps from there. (See our section about getting started with R notebooks if you are unfamiliar with .Rmd files.)

@@ -3950,7 +4000,7 @@

4.2 Import data

# desired gene list results dge_df <- readr::read_tsv(dge_url)
## 
-## ── Column specification ────────────────────────────────────────────────────────────────
+## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────
 ## cols(
 ##   Gene = col_character(),
 ##   logFC = col_double(),

From ba7e18c5c20f8d9d546d3357a6da227187d12806 Mon Sep 17 00:00:00 2001
From: jashapiro 
Date: Fri, 20 Nov 2020 17:13:31 -0500
Subject: [PATCH 42/50] Fix WGCNA installation (#366)

* Move order of install for WGCNA

* warn moar
---
 docker/Dockerfile | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/docker/Dockerfile b/docker/Dockerfile
index 0e2aa178..d4bd6146 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -35,9 +35,6 @@ RUN pip3 install \
 #### R packages
 ###############
 
-# We need to install impute so WGCNA will install in the next step
-RUN R -e "options(warn = 2); BiocManager::install('impute', update = FALSE)"
-
 # Commonly used R packages
 RUN Rscript -e  "install.packages( \
     c('cluster', \
@@ -48,12 +45,11 @@ RUN Rscript -e  "install.packages( \
       'rprojroot', \
       'viridis', \
       'spelling', \
-      'styler', \
-      'WGCNA'))"
+      'styler'))"
 
 # Install bioconductor packages
 # org.Mm.eg.db and org.Dr.eg.db are required for gene mapping
-RUN R -e "options(warn = 2); BiocManager::install( \
+RUN Rscript -e "options(warn = 2); BiocManager::install( \
     c('affy', \
       'apeglm', \
       'Biobase', \
@@ -62,6 +58,7 @@ RUN R -e "options(warn = 2); BiocManager::install( \
       'DESeq2', \
       'EnhancedVolcano', \
       'ggupset', \
+      'impute', \
       'limma', \
       'marray', \
       'msigdbr', \
@@ -85,6 +82,9 @@ RUN Rscript -e  "install.packages( \
 # Need this package to make plots colorblind friendly
 RUN Rscript -e "remotes::install_github('clauswilke/colorblindr', ref = '1ac3d4d62dad047b68bb66c06cee927a4517d678', dependencies = TRUE)"
 
+# Install WGCNA
+RUN Rscript -e  "options(warn = 2); install.packages('WGCNA')"
+
 # Install python libraries
 ##########################
 

From d6cfc8a6fa2d9548335991ad762be6a07fca9fa1 Mon Sep 17 00:00:00 2001
From: Chante Bethell <43576623+cbethell@users.noreply.github.com>
Date: Fri, 20 Nov 2020 17:40:01 -0500
Subject: [PATCH 43/50] Pr 1 of 2: Add Microarray Pathway Analysis - GSVA
 example (#359)

* Mechanics for CSS file and navbar add feedback URL (#303)

* Adding in some style with css

* Use css magic

* Try making the navbar blue

* Add survey link

* Make font smaller

* Need a comma

* Change to normalizePath

* normalizepath separate step references.bib

* Move references.bib to component folder

* Made ccs modifications, added logo file

Made changes to css/navbar.html
Tried to add the logo but it but it cuts out and not sure how to make it decent.

* Resolve render-notebooks.R conflict

* Remove testing html from file diff

* uncommented mobile nav

Co-authored-by: dvenprasad 

* Making staging changes live (#329)

* Adding in some style with css

* Use css magic

* Try making the navbar blue

* Add survey link

* Make font smaller

* Need a comma

* Change to normalizePath

* normalizepath separate step references.bib

* Move references.bib to component folder

* Update github actions to reflect staging branch (#311)

* Update github actions to reflect staging branch

* Add libglpk40 to Dockerfile

* Make it gh-pages-stages!

* Remove dockerfile change that should have been on its own all along

* Does this work?

* Declare a uses

* Switch how env is declared

* Force it to run so we can test it

* try no curly brackets

* What's up with the branch

* Move to bash if instead

* Need quotes?

* forgot a `then`

* Try dollar signs

* Doesn't like the `.`?

* Use curly brackets

* Try ${GITHUB_REF}

* Try ${BRANCH_NAME}

* try ${GITHUB_REF#refs/*/}

* use jashapiro suggestion

* Change to base ref

* Change back to `github.ref`

* Get rid of PR `on:`

* Try another test

* Docker dep fix: Add lib package 40 thing that clusterprofiler needs (#316)

* Add lib package 40 thing that clusterprofiler needs

* Try adding options(warn = 2)

* Test if options(warn =2) means it breaks like it should

* Revert "Test if options(warn =2) means it breaks like it should"

This reverts commit d9f688f68448ef69fe4c1caa48af23051cd7f4e3.

* Revert "Try another test"

This reverts commit 845cf1aff92ea7b83f402bbefd563562b44e5eac.

* Add google analytics to renderings (#314)

* Try adding google analytics

* Add to header using includes

* temporary file snuck in there

* Restore master version so they aren't in the review

* Let's call an html file and html file

* Docker dep fix: Add lib package 40 thing that clusterprofiler needs (#316)

* Add lib package 40 thing that clusterprofiler needs

* Try adding options(warn = 2)

* Test if options(warn =2) means it breaks like it should

* Revert "Test if options(warn =2) means it breaks like it should"

This reverts commit d9f688f68448ef69fe4c1caa48af23051cd7f4e3.

* Only push if we are in master.

For simplicity, we will now run this even if the dockerfile hasn't changed.

* Add test target

* test staging workflow with this branch

* back to latest tag

* Try separate push step

* change tags to test push

* Revert "change tags to test push"

This reverts commit 6a38574d312cee82c90c3c036ac9033f9af7f7ec.

* Remove this branch from triggers

* Push staging, retag and push master

Okay, so the branch name is now inaccurate, but that is fine...

* Made ccs modifications, added logo file

Made changes to css/navbar.html
Tried to add the logo but it but it cuts out and not sure how to make it decent.

* Resolve render-notebooks.R conflict

* Remove testing html from file diff

* uncommented mobile nav

* Update scripts/render-notebooks.R

* Add some issue templates (#319)

* Add some rough draft issue templates

* Incorporate cbethell review

* Get rid of `Other` labels that aren't useful

* Update diagrams showing how microarray/RNA-seq work  (#326)

* Mechanics for CSS file and navbar add feedback URL (#303)

* Adding in some style with css

* Use css magic

* Try making the navbar blue

* Add survey link

* Make font smaller

* Need a comma

* Change to normalizePath

* normalizepath separate step references.bib

* Move references.bib to component folder

* Made ccs modifications, added logo file

Made changes to css/navbar.html
Tried to add the logo but it but it cuts out and not sure how to make it decent.

* Resolve render-notebooks.R conflict

* Remove testing html from file diff

* uncommented mobile nav

Co-authored-by: dvenprasad 

* Update microarray and RNAseq overview figures


- add context re figures
- change .jpg to .png for consistency

* Revert "Mechanics for CSS file and navbar add feedback URL (#303)"

This reverts commit 8b81fdd96eeecf1d0e479d7908376b8e57dc356d.

* update links to diagrams

* @dvenprasad updated figure spacing

* add the right updated figure

* replace section of link to figures with updated commit id

* incorporate @cansavvy's suggested changes

Co-authored-by: Candace Savonen 
Co-authored-by: dvenprasad 

Co-authored-by: Joshua Shapiro 
Co-authored-by: dvenprasad 
Co-authored-by: Chante Bethell <43576623+cbethell@users.noreply.github.com>

* Add first half of microarray GSVA example notebook

* add packages to Dockerfile and rerun

* fix reference

* add to navbar

* remove mention of pheatmap

* incorporate @jaclyn-taroni's suggestion on collapsing duplicates logic

* incorporate cansavvy's review comments

- fix logic combing rest of mapped data with the collapsed duplicates data
- fix context around that logic

* clarify/change some wording based on cansavvy's suggestions

* incorporate single sample example of selecting max expression values

* Push code that cbethell and I chatted through

* Add to dictionary

* Style Rmds

* rerun Snakefile to update html file

* Apply jaclyn-taroni's wording suggestions from code review

Co-authored-by: Jaclyn Taroni 

* incorporate the rest of jaclyn-taroni's review suggestions

Co-authored-by: Candace Savonen 
Co-authored-by: dvenprasad 
Co-authored-by: Joshua Shapiro 
Co-authored-by: GitHub Actions 
Co-authored-by: Jaclyn Taroni 
---
 .../pathway-analysis_microarray_03_gsva.Rmd   |  424 ++
 .../pathway-analysis_microarray_03_gsva.html  | 4455 +++++++++++++++++
 Snakefile                                     |    1 +
 components/_navbar.html                       |    1 +
 components/dictionary.txt                     |    4 +
 components/references.bib                     |   46 +
 docker/Dockerfile                             |    4 +-
 7 files changed, 4934 insertions(+), 1 deletion(-)
 create mode 100644 02-microarray/pathway-analysis_microarray_03_gsva.Rmd
 create mode 100644 02-microarray/pathway-analysis_microarray_03_gsva.html

diff --git a/02-microarray/pathway-analysis_microarray_03_gsva.Rmd b/02-microarray/pathway-analysis_microarray_03_gsva.Rmd
new file mode 100644
index 00000000..31d8c51e
--- /dev/null
+++ b/02-microarray/pathway-analysis_microarray_03_gsva.Rmd
@@ -0,0 +1,424 @@
+---
+title: "Gene set variation analysis - Microarray"
+author: "CCDL for ALSF"
+date: "November 2020"
+output:  
+  html_notebook:
+    toc: true
+    toc_float: true
+    number_sections: true
+---
+
+# Purpose of this analysis
+
+This example is one of pathway analysis module set, we recommend looking at the [pathway analysis introduction](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_00_intro.html) to help you determine which pathway analysis method is best suited for your purposes.
+
+In this example we will cover a method called Gene Set Variation Analysis (GSVA) to calculate gene set or pathway scores on a per-sample basis.
+Gene set variation analysis (GSVA) constitutes a starting point to build pathway-centric models of biology.
+Rather than contextualizing some results you have received from another analysis like DGE, GSVA is designed to provide an estimate of pathway variation for each of the samples in an experiment.
+This means that GSVA scores will depend on the samples included in the dataset when you run GSVA; if you added more samples and ran GSVA again, you would expect the scores to change [@Hanzelmann2013].
+
+GSVA determines the relative enrichment of gene sets across samples using a non-parametric approach.
+GSVA transforms a gene by sample gene expression matrix into a gene set by sample pathway enrichment matrix [@Hanzelmann-github].
+
+⬇️ [**Jump to the analysis code**](#analysis) ⬇️
+
+# How to run this example
+
+For general information about our tutorials and the basic software packages you will need, please see our ['Getting Started' section](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-this-tutorial-is-structured).
+We recommend taking a look at our [Resources for Learning R](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#resources-for-learning-r) if you have not written code in R before. 
+
+## Obtain the `.Rmd` file
+
+To run this example yourself, [download the `.Rmd` for this analysis by clicking this link](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_03_gsva.Rmd).
+
+Clicking this link will most likely send this to your downloads folder on your computer. 
+Move this `.Rmd` file to where you would like this example and its files to be stored.
+
+You can open this `.Rmd` file in RStudio and follow the rest of these steps from there. (See our [section about getting started with R notebooks](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-and-use-rmds) if you are unfamiliar with `.Rmd` files.)
+
+## Set up your analysis folders 
+
+Good file organization is helpful for keeping your data analysis project on track!
+We have set up some code that will automatically set up a folder structure for you. 
+Run this next chunk to set up your folders! 
+
+If you have trouble running this chunk, see our [introduction to using `.Rmd`s](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-and-use-rmds) for more resources and explanations. 
+
+```{r}
+# Create the data folder if it doesn't exist
+if (!dir.exists("data")) {
+  dir.create("data")
+}
+
+# Define the file path to the plots directory
+plots_dir <- "plots" # Can replace with path to desired output plots directory
+
+# Create the plots folder if it doesn't exist
+if (!dir.exists(plots_dir)) {
+  dir.create(plots_dir)
+}
+
+# Define the file path to the results directory
+results_dir <- "results" # Can replace with path to desired output results directory
+
+# Create the results folder if it doesn't exist
+if (!dir.exists(results_dir)) {
+  dir.create(results_dir)
+}
+```
+
+In the same place you put this `.Rmd` file, you should now have three new empty folders called `data`, `plots`, and `results`!
+
+## Obtain the dataset from refine.bio
+
+For general information about downloading data for these examples, see our ['Getting Started' section](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-the-data). 
+
+Go to this [dataset's page on refine.bio](https://www.refine.bio/experiments/GSE7696/glioblastoma-from-a-homogenous-cohort-of-patients-treated-within-clinical-trial).
+
+Click the "Download Now" button on the right side of this screen.  
+
+  
+
+Fill out the pop up window with your email and our Terms and Conditions:  
+
+  
+
+It may take a few minutes for the dataset to process.
+You will get an email when it is ready.
+
+## About the dataset we are using for this example
+
+For this example analysis, we will use this [glioblastoma dataset](https://www.refine.bio/experiments/GSE7696/glioblastoma-from-a-homogenous-cohort-of-patients-treated-within-clinical-trial).
+
+This dataset contains the measured microarray gene expression of 79 glioblastoma samples from a homogenous cohort of clinical patients.
+
+## Place the dataset in your new `data/` folder
+
+refine.bio will send you a download button in the email when it is ready. 
+Follow the prompt to download a zip file that has a name with a series of letters and numbers and ends in `.zip`. 
+Double clicking should unzip this for you and create a folder of the same name.  
+
+ 
+
+For more details on the contents of this folder see [these docs on refine.bio](http://docs.refine.bio/en/latest/main_text.html#downloadable-files).  
+
+The `GSE7696` folder has the data and metadata TSV files you will need for this example analysis.
+Experiment accession ids usually look something like `GSE1235` or `SRP12345`. 
+
+Copy and paste the `GSE7696` folder into your newly created `data/` folder.
+
+## Check out our file structure!
+
+Your new analysis folder should contain: 
+
+- The example analysis `.Rmd` you downloaded  
+- A folder called "data" which contains:
+  - The `GSE7696` folder which contains:
+    - The gene expression  
+    - The metadata TSV  
+- A folder for `plots` (currently empty)  
+- A folder for `results` (currently empty)  
+    
+Your example analysis folder should now look something like this (except with respective experiment accession ID and analysis notebook name you are using): 
+
+
+
+In order for our example here to run without a hitch, we need these files to be in these locations so we've constructed a test to check before we get started with the analysis. 
+These chunks will declare your file paths and double check that your files are in the right place. 
+
+First we will declare our file paths to our data and metadata files, which should be in our data directory.
+This is handy to do because if we want to switch the dataset (see next section for more on this) we are using for this analysis, we will only have to change the file path here to get started.  
+
+```{r}
+# Define the file path to the data directory
+data_dir <- file.path("data", "GSE7696") # Replace with accession number which will be the name of the folder the files will be in
+
+# Declare the file path to the gene expression matrix file using the data directory saved as `data_dir`
+data_file <- file.path(data_dir, "GSE7696.tsv") # Replace with file path to your dataset
+
+# Declare the file path to the metadata file using the data directory saved as `data_dir`
+metadata_file <- file.path(data_dir, "metadata_GSE7696.tsv") # Replace with file path to your metadata
+```
+
+Now that our file paths are declared, we can use the `file.exists()` function to check that the files are where we specified above.  
+
+```{r}
+# Check if the gene expression matrix file is at the file path stored in `data_file`
+file.exists(data_file)
+
+# Check if the metadata file is at the file path stored in `metadata_file`
+file.exists(metadata_file)
+```
+
+If the chunk above printed out `FALSE` to either of those tests, you won't be able to run this analysis _as is_ until those files are in the appropriate place.
+
+If the concept of a "file path" is unfamiliar to you; we recommend taking a look at our [section about file paths](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#an-important-note-about-file-paths-and-Rmds). 
+
+# Using a different refine.bio dataset with this analysis?
+
+If you'd like to adapt an example analysis to use a different dataset from [refine.bio](https://www.refine.bio/), we recommend placing the files in the `data/` directory you created and changing the filenames and paths in the notebook to match these files (we've put comments to signify where you would need to change the code).
+We suggest saving plots and results to `plots/` and `results/` directories, respectively, as these are automatically created by the notebook.
+From here you can customize this analysis example to fit your own scientific questions and preferences. 
+
+***
+
+  
+
+# Gene set variation analysis - Microarray
+
+## Install libraries
+
+See our Getting Started page with [instructions for package installation](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#what-you-need-to-install) for a list of the other software you will need, as well as more tips and resources.
+
+In this analysis, we will be using the [`GSVA`](https://www.bioconductor.org/packages/release/bioc/html/GSVA.html) package to perform GSVA and the [`qusage`](https://www.bioconductor.org/packages/release/bioc/html/qusage.html) package to read in the GMT file containing the gene set data [@Hanzelmann2013; @Meng2019].
+
+We will also need the [`org.Hs.eg.db`](https://bioconductor.org/packages/release/data/annotation/html/org.Hs.eg.db.html) package to perform gene identifier conversion [@Carlson2020-human].
+
+```{r}
+if (!("GSVA" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("GSVA", update = FALSE)
+}
+
+if (!("qusage" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("qusage", update = FALSE)
+}
+
+if (!("org.Hs.eg.db" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("org.Hs.eg.db", update = FALSE)
+}
+```
+
+Attach the packages we need for this analysis.
+
+```{r}
+# Attach the `qusage` library
+library(qusage)
+
+# Attach the `GSVA` library
+library(GSVA)
+
+# Human annotation package we'll use for gene identifier conversion
+library(org.Hs.eg.db)
+
+# We will need this so we can use the pipe: %>%
+library(magrittr)
+```
+
+## Import and set up data
+
+Data downloaded from refine.bio include a metadata tab separated values (TSV) file and a data TSV file. 
+This chunk of code will read both TSV files and add them as data frames to your environment.
+
+We stored our file paths as objects named `metadata_file` and `data_file` in [this previous step](#check-out-our-file-structure).
+
+```{r}
+# Read in metadata TSV file
+metadata <- readr::read_tsv(metadata_file)
+
+# Read in data TSV file
+expression_df <- readr::read_tsv(data_file) %>%
+  # Tuck away the gene ID  column as row names
+  tibble::column_to_rownames("Gene")
+```
+
+Let's ensure that the metadata and data are in the same sample order. 
+
+```{r}
+# Make the data in the order of the metadata
+expression_df <- expression_df %>%
+  dplyr::select(metadata$geo_accession)
+
+# Check if this is in the same order
+all.equal(colnames(expression_df), metadata$geo_accession)
+
+# Bring back the "Gene" column in preparation for mapping
+expression_df <- expression_df %>%
+  tibble::rownames_to_column("Gene")
+```
+
+### Import Gene Sets
+
+The function that we will use to run GSVA wants the gene sets to be in a list, rather than a tidy data frame.
+
+We are therefore going to read in the Hallmark collection of gene sets file directly from [MSigDB](https://www.gsea-msigdb.org/gsea/msigdb/index.jsp), rather than using the [`msigdbr`](https://cran.r-project.org/web/packages/msigdbr/index.html) package like we did in earlier notebooks [@Igor2020].
+
+Note that when reading in the Hallmark collection file in this manner, the data is only compatible with _Homo sapiens_ datasets.
+
+```{r}
+# R can often read in data from a URL
+hallmarks_url <- "https://data.broadinstitute.org/gsea-msigdb/msigdb/release/7.2/h.all.v7.2.entrez.gmt"
+
+# QuSAGE is another pathway analysis method, the `qusage` package has a function
+# for reading GMT files and turning them into a list
+hallmarks_list <- qusage::read.gmt(hallmarks_url)
+```
+
+What does this `hallmarks_list` look like?
+
+```{r}
+head(hallmarks_list)
+```
+
+Looks like we have a list of gene sets with associated Entrez IDs.
+
+In our gene expression data frame, `expression_df` we have Ensembl gene identifiers.
+So we will need to convert our Ensembl IDs into Entrez IDs for GSVA.
+
+### Gene identifier conversion
+
+We're going to convert our identifiers in `expression_df` to Entrez IDs, but you can, with the change of a single argument, use the same code to convert to many other types of identifiers!
+
+The annotation package `org.Hs.eg.db` contains information for different identifiers [@Carlson2020-human].
+`org.Hs.eg.db` is specific to _Homo sapiens_ -- this is what the `Hs` in the package name is referencing.
+
+We can see what types of IDs are available to us in an annotation package with `keytypes()`.
+
+```{r}
+keytypes(org.Hs.eg.db)
+```
+
+Even though we'll use this package to convert from Ensembl gene IDs (`ENSEMBL`) to Entrez IDs (`ENTREZID`), we could just as easily use it to convert from an Ensembl transcript ID (`ENSEMBLTRANS`) to gene symbols (`SYMBOL`).
+
+Take a look at our other gene identifier conversion examples for examples with different species and gene ID types:
+[the microarray example](https://alexslemonade.github.io/refinebio-examples/02-microarray/gene-id-annotation_microarray_01_ensembl.html) and [the RNA-seq example](https://alexslemonade.github.io/refinebio-examples/03-rnaseq/gene-id-annotation_rnaseq_01_ensembl.html).
+
+The function we will use to map from Ensembl gene IDs to Entrez gene IDs is called `mapIds()`.
+
+Let's create a data frame that shows the mapped Entrez IDs along with the gene expression values for the respective Ensembl IDs.
+
+```{r}
+# First let's create a mapped data frame we can join to the gene expression values
+mapped_df <- data.frame(
+  "entrez_id" = mapIds(
+    org.Hs.eg.db, # Replace with annotation package for the organism relevant to your data
+    keys = expression_df$Gene,
+    column = "ENTREZID", # Replace with the type of gene identifiers you would like to map to
+    keytype = "ENSEMBL", # Replace with the type of gene identifiers in your data
+    multiVals = "first" # This will keep only the first mapped value for each Ensembl ID
+  )
+) %>%
+  # If an Ensembl gene identifier doesn't map to a Entrez gene identifier, drop that
+  # from the data frame
+  dplyr::filter(!is.na(entrez_id)) %>%
+  # Make an `Ensembl` column to store the row names
+  tibble::rownames_to_column("Ensembl") %>%
+  # Now let's join the rest of the expression data
+  dplyr::inner_join(expression_df, by = c("Ensembl" = "Gene")) %>%
+  # We won't be using Ensembl IDs moving forward, so we will drop this column
+  dplyr::select(-Ensembl)
+```
+
+This `1:many mapping between keys and columns` message means that some Ensembl gene identifiers map to multiple Entrez IDs.
+In this case, it's also possible that a Entrez ID will map to multiple Ensembl IDs.
+For the purpose of performing GSVA later in this notebook, we keep only the first mapped IDs.
+For more about how to explore this, take a look at our [microarray gene ID conversion example](https://alexslemonade.github.io/refinebio-examples/02-microarray/gene-id-annotation_microarray_01_ensembl.html).
+
+Let's see a preview of `mapped_df`.
+
+```{r}
+head(mapped_df)
+```
+
+We will want to keep in mind that GSVA requires that data is in a matrix with the gene identifiers as row names.
+In order to successfully turn our data frame into a matrix, we will need to ensure that we do not have any duplicate gene identifiers.
+
+Let's check to see if we have any Entrez IDs that mapped to multiple Ensembl IDs.
+
+```{r}
+any(duplicated(mapped_df$entrez_id))
+```
+
+Looks like we do have duplicated Entrez IDs.
+Let's find out which Entrez IDs have been duplicated.
+
+```{r}
+dup_entrez_ids <- mapped_df %>%
+  dplyr::filter(duplicated(entrez_id)) %>%
+  dplyr::pull(entrez_id)
+
+dup_entrez_ids
+```
+
+#### Handling duplicate gene identifiers
+
+As we mentioned earlier, we will not want any duplicate gene identifiers in our data frame when we convert it into a matrix in preparation for the GSVA steps later.
+GSVA is executed on a per sample basis so let's keep the maximum expression value per sample associated with the duplicate Entrez gene identifiers.
+In other words, we will keep only the maximum expression value found across the duplicate Entrez gene identifier instances for each sample or column in this case.
+
+Let's take a look at the rows associated with the duplicated Entrez IDs and see how this will play out. 
+
+```{r}
+mapped_df %>%
+  dplyr::filter(entrez_id %in% dup_entrez_ids)
+```
+
+As an example using the strategy we described, for `GSM187153`'s data in the first column, `-0.007355525` is larger than `-0.136553967` so moving forward, Entrez gene `6013` will have `-0.007355525` value and the `-0.136553967` would be dropped from the dataset. 
+
+However, this is just one method of handling duplicate gene identifiers.
+See the [Gene Set Enrichment Analysis (GSEA) User guide](https://www.gsea-msigdb.org/gsea/doc/GSEAUserGuideFrame.html) for more information on other expression values that can be used, like the median expression value for example [@GSEA-user-guide].
+
+Now, let's implement our choose the max value method for all samples and Entrez IDs using tidyverse functions. 
+
+```{r}
+max_dup_df <- mapped_df %>%
+  # Filter to include only the rows associated with the duplicate Entrez gene identifiers
+  dplyr::filter(entrez_id %in% dup_entrez_ids) %>%
+  # Group by Entrez IDs
+  dplyr::group_by(entrez_id) %>%
+  # Get the maximum expression value using all values associated with each duplicate
+  # Entrez ID for each column or sample in this case
+  dplyr::summarize_all(max)
+
+max_dup_df
+```
+
+We can see `GSM187153` now has the `-0.007355525` value for Entrez ID `6013` like expected.
+
+Looks like we were able to successfully get rid of the duplicate Entrez gene identifiers!
+
+Now let's combine our de-duplicated data with the rest of the mapped data!
+
+```{r}
+filtered_mapped_df <- mapped_df %>%
+  # First let's get the data associated with the Entrez gene identifiers that aren't duplicated
+  dplyr::filter(!entrez_id %in% dup_entrez_ids) %>%
+  # Now let's bind the rows of the maximum expression data we stored in `max_dup_df`
+  dplyr::bind_rows(max_dup_df)
+```
+ 
+As mentioned earlier, we need a matrix for GSVA.
+Let's now convert our data frame into a matrix and prepare our object for GSVA.
+
+```{r}
+filtered_mapped_matrix <- filtered_mapped_df %>%
+  # We need to store our gene identifiers as row names
+  tibble::column_to_rownames("entrez_id") %>%
+  # Now we can convert our object into a matrix
+  as.matrix()
+```
+
+Note that if we had duplicate gene identifiers here, we would not be able to set them as row names.
+
+## GSVA - Microarray
+
+_Addressed in upcoming PR_
+
+# Resources for further learning
+
+_Addressed in upcoming PR_
+
+# Session info
+
+At the end of every analysis, before saving your notebook, we recommend printing out your session info. 
+This helps make your code more reproducible by recording what versions of software and packages you used to run this. 
+
+```{r}
+# Print session info
+sessioninfo::session_info()
+```
+
+# References
diff --git a/02-microarray/pathway-analysis_microarray_03_gsva.html b/02-microarray/pathway-analysis_microarray_03_gsva.html
new file mode 100644
index 00000000..baf4b7fd
--- /dev/null
+++ b/02-microarray/pathway-analysis_microarray_03_gsva.html
@@ -0,0 +1,4455 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Gene set variation analysis - Microarray
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
+ + + + + + + + + +
+

1 Purpose of this analysis

+

This example is one of pathway analysis module set, we recommend looking at the pathway analysis introduction to help you determine which pathway analysis method is best suited for your purposes.

+

In this example we will cover a method called Gene Set Variation Analysis (GSVA) to calculate gene set or pathway scores on a per-sample basis. Gene set variation analysis (GSVA) constitutes a starting point to build pathway-centric models of biology. Rather than contextualizing some results you have received from another analysis like DGE, GSVA is designed to provide an estimate of pathway variation for each of the samples in an experiment. This means that GSVA scores will depend on the samples included in the dataset when you run GSVA; if you added more samples and ran GSVA again, you would expect the scores to change (Hänzelmann et al. 2013a).

+

GSVA determines the relative enrichment of gene sets across samples using a non-parametric approach. GSVA transforms a gene by sample gene expression matrix into a gene set by sample pathway enrichment matrix (Hänzelmann et al. 2013b).

+

⬇️ Jump to the analysis code ⬇️

+
+
+

2 How to run this example

+

For general information about our tutorials and the basic software packages you will need, please see our ‘Getting Started’ section. We recommend taking a look at our Resources for Learning R if you have not written code in R before.

+
+

2.1 Obtain the .Rmd file

+

To run this example yourself, download the .Rmd for this analysis by clicking this link.

+

Clicking this link will most likely send this to your downloads folder on your computer. Move this .Rmd file to where you would like this example and its files to be stored.

+

You can open this .Rmd file in RStudio and follow the rest of these steps from there. (See our section about getting started with R notebooks if you are unfamiliar with .Rmd files.)

+
+
+

2.2 Set up your analysis folders

+

Good file organization is helpful for keeping your data analysis project on track! We have set up some code that will automatically set up a folder structure for you. Run this next chunk to set up your folders!

+

If you have trouble running this chunk, see our introduction to using .Rmds for more resources and explanations.

+
# Create the data folder if it doesn't exist
+if (!dir.exists("data")) {
+  dir.create("data")
+}
+
+# Define the file path to the plots directory
+plots_dir <- "plots" # Can replace with path to desired output plots directory
+
+# Create the plots folder if it doesn't exist
+if (!dir.exists(plots_dir)) {
+  dir.create(plots_dir)
+}
+
+# Define the file path to the results directory
+results_dir <- "results" # Can replace with path to desired output results directory
+
+# Create the results folder if it doesn't exist
+if (!dir.exists(results_dir)) {
+  dir.create(results_dir)
+}
+

In the same place you put this .Rmd file, you should now have three new empty folders called data, plots, and results!

+
+
+

2.3 Obtain the dataset from refine.bio

+

For general information about downloading data for these examples, see our ‘Getting Started’ section.

+

Go to this dataset’s page on refine.bio.

+

Click the “Download Now” button on the right side of this screen.

+

+

Fill out the pop up window with your email and our Terms and Conditions:

+

+

It may take a few minutes for the dataset to process. You will get an email when it is ready.

+
+
+

2.4 About the dataset we are using for this example

+

For this example analysis, we will use this glioblastoma dataset.

+

This dataset contains the measured microarray gene expression of 79 glioblastoma samples from a homogenous cohort of clinical patients.

+
+
+

2.5 Place the dataset in your new data/ folder

+

refine.bio will send you a download button in the email when it is ready. Follow the prompt to download a zip file that has a name with a series of letters and numbers and ends in .zip. Double clicking should unzip this for you and create a folder of the same name.

+

+

For more details on the contents of this folder see these docs on refine.bio.

+

The GSE7696 folder has the data and metadata TSV files you will need for this example analysis. Experiment accession ids usually look something like GSE1235 or SRP12345.

+

Copy and paste the GSE7696 folder into your newly created data/ folder.

+
+
+

2.6 Check out our file structure!

+

Your new analysis folder should contain:

+
    +
  • The example analysis .Rmd you downloaded
    +
  • +
  • A folder called “data” which contains: +
      +
    • The GSE7696 folder which contains: +
        +
      • The gene expression
        +
      • +
      • The metadata TSV
        +
      • +
    • +
  • +
  • A folder for plots (currently empty)
    +
  • +
  • A folder for results (currently empty)
  • +
+

Your example analysis folder should now look something like this (except with respective experiment accession ID and analysis notebook name you are using):

+

+

In order for our example here to run without a hitch, we need these files to be in these locations so we’ve constructed a test to check before we get started with the analysis. These chunks will declare your file paths and double check that your files are in the right place.

+

First we will declare our file paths to our data and metadata files, which should be in our data directory. This is handy to do because if we want to switch the dataset (see next section for more on this) we are using for this analysis, we will only have to change the file path here to get started.

+
# Define the file path to the data directory
+data_dir <- file.path("data", "GSE7696") # Replace with accession number which will be the name of the folder the files will be in
+
+# Declare the file path to the gene expression matrix file using the data directory saved as `data_dir`
+data_file <- file.path(data_dir, "GSE7696.tsv") # Replace with file path to your dataset
+
+# Declare the file path to the metadata file using the data directory saved as `data_dir`
+metadata_file <- file.path(data_dir, "metadata_GSE7696.tsv") # Replace with file path to your metadata
+

Now that our file paths are declared, we can use the file.exists() function to check that the files are where we specified above.

+
# Check if the gene expression matrix file is at the file path stored in `data_file`
+file.exists(data_file)
+
## [1] TRUE
+
# Check if the metadata file is at the file path stored in `metadata_file`
+file.exists(metadata_file)
+
## [1] TRUE
+

If the chunk above printed out FALSE to either of those tests, you won’t be able to run this analysis as is until those files are in the appropriate place.

+

If the concept of a “file path” is unfamiliar to you; we recommend taking a look at our section about file paths.

+
+
+
+

3 Using a different refine.bio dataset with this analysis?

+

If you’d like to adapt an example analysis to use a different dataset from refine.bio, we recommend placing the files in the data/ directory you created and changing the filenames and paths in the notebook to match these files (we’ve put comments to signify where you would need to change the code). We suggest saving plots and results to plots/ and results/ directories, respectively, as these are automatically created by the notebook. From here you can customize this analysis example to fit your own scientific questions and preferences.

+
+ +

 

+
+
+

4 Gene set variation analysis - Microarray

+
+

4.1 Install libraries

+

See our Getting Started page with instructions for package installation for a list of the other software you will need, as well as more tips and resources.

+

In this analysis, we will be using the GSVA package to perform GSVA and the qusage package to read in the GMT file containing the gene set data (Hänzelmann et al. 2013a; Meng et al. 2019).

+

We will also need the org.Hs.eg.db package to perform gene identifier conversion (Carlson 2020).

+
if (!("GSVA" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("GSVA", update = FALSE)
+}
+
+if (!("qusage" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("qusage", update = FALSE)
+}
+
+if (!("org.Hs.eg.db" %in% installed.packages())) {
+  # Install this package if it isn't installed yet
+  BiocManager::install("org.Hs.eg.db", update = FALSE)
+}
+

Attach the packages we need for this analysis.

+
# Attach the `qusage` library
+library(qusage)
+
## Loading required package: limma
+
# Attach the `GSVA` library
+library(GSVA)
+
+# Human annotation package we'll use for gene identifier conversion
+library(org.Hs.eg.db)
+
## Loading required package: AnnotationDbi
+
## Loading required package: stats4
+
## Loading required package: BiocGenerics
+
## Loading required package: parallel
+
## 
+## Attaching package: 'BiocGenerics'
+
## The following objects are masked from 'package:parallel':
+## 
+##     clusterApply, clusterApplyLB, clusterCall, clusterEvalQ,
+##     clusterExport, clusterMap, parApply, parCapply, parLapply,
+##     parLapplyLB, parRapply, parSapply, parSapplyLB
+
## The following object is masked from 'package:limma':
+## 
+##     plotMA
+
## The following objects are masked from 'package:stats':
+## 
+##     IQR, mad, sd, var, xtabs
+
## The following objects are masked from 'package:base':
+## 
+##     anyDuplicated, append, as.data.frame, basename, cbind, colnames,
+##     dirname, do.call, duplicated, eval, evalq, Filter, Find, get, grep,
+##     grepl, intersect, is.unsorted, lapply, Map, mapply, match, mget,
+##     order, paste, pmax, pmax.int, pmin, pmin.int, Position, rank,
+##     rbind, Reduce, rownames, sapply, setdiff, sort, table, tapply,
+##     union, unique, unsplit, which.max, which.min
+
## Loading required package: Biobase
+
## Welcome to Bioconductor
+## 
+##     Vignettes contain introductory material; view with
+##     'browseVignettes()'. To cite Bioconductor, see
+##     'citation("Biobase")', and for packages 'citation("pkgname")'.
+
## Loading required package: IRanges
+
## Loading required package: S4Vectors
+
## 
+## Attaching package: 'S4Vectors'
+
## The following object is masked from 'package:base':
+## 
+##     expand.grid
+
## 
+
# We will need this so we can use the pipe: %>%
+library(magrittr)
+
+
+

4.2 Import and set up data

+

Data downloaded from refine.bio include a metadata tab separated values (TSV) file and a data TSV file. This chunk of code will read both TSV files and add them as data frames to your environment.

+

We stored our file paths as objects named metadata_file and data_file in this previous step.

+
# Read in metadata TSV file
+metadata <- readr::read_tsv(metadata_file)
+
## 
+## ── Column specification ─────────────────────────────────────────────────────────────────────
+## cols(
+##   .default = col_character(),
+##   refinebio_age = col_double(),
+##   refinebio_cell_line = col_logical(),
+##   refinebio_compound = col_logical(),
+##   refinebio_disease_stage = col_logical(),
+##   refinebio_genetic_information = col_logical(),
+##   refinebio_processed = col_logical(),
+##   refinebio_race = col_logical(),
+##   refinebio_source_archive_url = col_logical(),
+##   refinebio_time = col_logical(),
+##   age = col_double(),
+##   channel_count = col_double(),
+##   `contact_zip/postal_code` = col_double(),
+##   data_row_count = col_double(),
+##   `survival status` = col_double(),
+##   `survival time in months` = col_double(),
+##   taxid_ch1 = col_double()
+## )
+## ℹ Use `spec()` for the full column specifications.
+
# Read in data TSV file
+expression_df <- readr::read_tsv(data_file) %>%
+  # Tuck away the gene ID  column as row names
+  tibble::column_to_rownames("Gene")
+
## 
+## ── Column specification ─────────────────────────────────────────────────────────────────────
+## cols(
+##   .default = col_double(),
+##   Gene = col_character()
+## )
+## ℹ Use `spec()` for the full column specifications.
+

Let’s ensure that the metadata and data are in the same sample order.

+
# Make the data in the order of the metadata
+expression_df <- expression_df %>%
+  dplyr::select(metadata$geo_accession)
+
+# Check if this is in the same order
+all.equal(colnames(expression_df), metadata$geo_accession)
+
## [1] TRUE
+
# Bring back the "Gene" column in preparation for mapping
+expression_df <- expression_df %>%
+  tibble::rownames_to_column("Gene")
+
+

4.2.1 Import Gene Sets

+

The function that we will use to run GSVA wants the gene sets to be in a list, rather than a tidy data frame.

+

We are therefore going to read in the Hallmark collection of gene sets file directly from MSigDB, rather than using the msigdbr package like we did in earlier notebooks (Dolgalev 2020).

+

Note that when reading in the Hallmark collection file in this manner, the data is only compatible with Homo sapiens datasets.

+
# R can often read in data from a URL
+hallmarks_url <- "https://data.broadinstitute.org/gsea-msigdb/msigdb/release/7.2/h.all.v7.2.entrez.gmt"
+
+# QuSAGE is another pathway analysis method, the `qusage` package has a function
+# for reading GMT files and turning them into a list
+hallmarks_list <- qusage::read.gmt(hallmarks_url)
+

What does this hallmarks_list look like?

+
head(hallmarks_list)
+
## $HALLMARK_TNFA_SIGNALING_VIA_NFKB
+##   [1] "3726"   "2920"   "467"    "4792"   "7128"   "5743"   "2919"   "8870"  
+##   [9] "9308"   "6364"   "2921"   "23764"  "4791"   "7127"   "1839"   "1316"  
+##  [17] "330"    "5329"   "7538"   "3383"   "3725"   "1960"   "3553"   "597"   
+##  [25] "23645"  "80149"  "6648"   "4929"   "3552"   "5971"   "7185"   "7832"  
+##  [33] "1843"   "1326"   "2114"   "2152"   "6385"   "1958"   "3569"   "7124"  
+##  [41] "23135"  "4790"   "3976"   "5806"   "8061"   "3164"   "182"    "6351"  
+##  [49] "2643"   "6347"   "1827"   "1844"   "10938"  "9592"   "5966"   "8837"  
+##  [57] "8767"   "4794"   "8013"   "22822"  "51278"  "8744"   "2669"   "1647"  
+##  [65] "3627"   "10769"  "8553"   "1959"   "9021"   "11182"  "5734"   "1847"  
+##  [73] "5055"   "4783"   "5054"   "10221"  "25976"  "5970"   "329"    "6372"  
+##  [81] "9516"   "7130"   "960"    "3624"   "5328"   "4609"   "3604"   "6446"  
+##  [89] "10318"  "10135"  "2355"   "10957"  "3398"   "969"    "3575"   "1942"  
+##  [97] "7262"   "5209"   "6352"   "79693"  "3460"   "8878"   "10950"  "4616"  
+## [105] "8942"   "50486"  "694"    "4170"   "7422"   "5606"   "1026"   "3491"  
+## [113] "10010"  "3433"   "3606"   "7280"   "3659"   "2353"   "4973"   "388"   
+## [121] "374"    "4814"   "65986"  "8613"   "9314"   "6373"   "6303"   "1435"  
+## [129] "1880"   "56937"  "5791"   "7097"   "57007"  "7071"   "4082"   "3914"  
+## [137] "1051"   "9322"   "2150"   "687"    "3949"   "7050"   "127544" "55332" 
+## [145] "2683"   "11080"  "1437"   "5142"   "8303"   "5341"   "6776"   "23258" 
+## [153] "595"    "23586"  "8877"   "941"    "25816"  "57018"  "2526"   "9034"  
+## [161] "80176"  "8848"   "9334"   "150094" "23529"  "4780"   "2354"   "5187"  
+## [169] "10725"  "490"    "3593"   "3572"   "9120"   "19"     "3280"   "604"   
+## [177] "8660"   "6515"   "1052"   "51561"  "4088"   "6890"   "9242"   "64135" 
+## [185] "3601"   "79155"  "602"    "24145"  "24147"  "1906"   "10209"  "650"   
+## [193] "1846"   "10611"  "23308"  "9945"   "10365"  "3371"   "5271"   "4084"  
+## 
+## $HALLMARK_HYPOXIA
+##   [1] "5230"   "5163"   "2632"   "5211"   "226"    "2026"   "5236"   "10397" 
+##   [9] "3099"   "230"    "2821"   "4601"   "6513"   "5033"   "133"    "8974"  
+##  [17] "2023"   "5214"   "205"    "26355"  "5209"   "7422"   "665"    "7167"  
+##  [25] "30001"  "55818"  "901"    "3939"   "2997"   "2597"   "8553"   "51129" 
+##  [33] "3725"   "5054"   "4015"   "2645"   "8497"   "23764"  "54541"  "6515"  
+##  [41] "3486"   "4783"   "2353"   "3516"   "3098"   "10370"  "3669"   "2584"  
+##  [49] "26118"  "5837"   "6781"   "23036"  "694"    "123"    "1466"   "7436"  
+##  [57] "23210"  "2131"   "2152"   "5165"   "55139"  "7360"   "229"    "8614"  
+##  [65] "54206"  "2027"   "10957"  "3162"   "5228"   "26330"  "9435"   "55076" 
+##  [73] "63827"  "467"    "857"    "272"    "2719"   "3340"   "8660"   "8819"  
+##  [81] "2548"   "6385"   "8987"   "8870"   "5313"   "3484"   "5329"   "112464"
+##  [89] "8839"   "9215"   "25819"  "6275"   "58528"  "7538"   "1956"   "1907"  
+##  [97] "3423"   "1026"   "6095"   "1843"   "4282"   "5507"   "10570"  "11015" 
+## [105] "1837"   "136"    "9957"   "284119" "2908"   "1316"   "2239"   "3491"  
+## [113] "7128"   "771"    "3073"   "633"    "23645"  "55276"  "5292"   "25824" 
+## [121] "55577"  "1027"   "680"    "8277"   "4493"   "538"    "4502"   "9672"  
+## [129] "25976"  "5317"   "302"    "5224"   "1649"   "5578"   "2542"   "7852"  
+## [137] "1944"   "1356"   "8609"   "1490"   "9469"   "7163"   "56925"  "124872"
+## [145] "10891"  "596"    "2651"   "3036"   "54800"  "949"    "6576"   "6383"  
+## [153] "839"    "7428"   "2309"   "5155"   "126792" "6518"   "8406"   "1942"  
+## [161] "2745"   "57007"  "5066"   "7045"   "1634"   "6478"   "51316"  "2203"  
+## [169] "8459"   "5260"   "4627"   "1028"   "9380"   "5105"   "3623"   "3309"  
+## [177] "8509"   "23327"  "7162"   "7511"   "3569"   "6533"   "4214"   "3948"  
+## [185] "9590"   "26136"  "3798"   "3906"   "1289"   "2817"   "3069"   "10994" 
+## [193] "1463"   "7052"   "2113"   "3219"   "8991"   "2355"   "6820"   "7043"  
+## 
+## $HALLMARK_CHOLESTEROL_HOMEOSTASIS
+##  [1] "2224"   "1595"   "3422"   "2222"   "1717"   "6713"   "3157"   "50814" 
+##  [9] "4047"   "4597"   "3949"   "7108"   "230"    "10682"  "6319"   "10654" 
+## [17] "4598"   "4023"   "6309"   "9415"   "3156"   "51478"  "312"    "6721"  
+## [25] "5833"   "55902"  "467"    "127"    "23474"  "1891"   "875"    "2990"  
+## [33] "2194"   "3958"   "22809"  "308"    "94241"  "1119"   "2946"   "39"    
+## [41] "552"    "5359"   "1191"   "54206"  "57761"  "58191"  "51330"  "71"    
+## [49] "182"    "5641"   "26270"  "493869" "10957"  "118429" "114569" "928"   
+## [57] "5468"   "2731"   "6811"   "134429" "1499"   "27346"  "116496" "5165"  
+## [65] "5329"   "7869"   "2770"   "20"     "6311"   "4783"   "214"    "2171"  
+## [73] "6282"   "132864"
+## 
+## $HALLMARK_MITOTIC_SPINDLE
+##   [1] "9181"   "23332"  "3832"   "9493"   "57679"  "382"    "4650"   "4627"  
+##   [9] "10426"  "9793"   "29127"  "57580"  "50650"  "4926"   "6711"   "11004" 
+##  [17] "3799"   "7272"   "324"    "11190"  "5048"   "10435"  "9371"   "55704" 
+##  [25] "56992"  "332"    "116840" "4763"   "7248"   "996"    "11064"  "114791"
+##  [33] "24137"  "22919"  "55785"  "675"    "5347"   "5921"   "4751"   "8936"  
+##  [41] "7153"   "7204"   "9826"   "10300"  "9055"   "54443"  "55755"  "9126"  
+##  [49] "10844"  "9700"   "55201"  "201176" "9732"   "29901"  "3619"   "394"   
+##  [57] "2934"   "10276"  "10128"  "23637"  "2317"   "64411"  "121512" "29"    
+##  [65] "55835"  "4690"   "1063"   "9585"   "10163"  "4628"   "1062"   "9266"  
+##  [73] "4281"   "3831"   "57787"  "127829" "9702"   "8409"   "393"    "23580" 
+##  [81] "163786" "9113"   "4983"   "8976"   "4296"   "6654"   "25"     "7074"  
+##  [89] "23095"  "6453"   "134549" "8440"   "9787"   "613"    "10048"  "2037"  
+##  [97] "10801"  "11104"  "51174"  "22974"  "3797"   "357"    "85378"  "6709"  
+## [105] "23022"  "23647"  "9735"   "84376"  "25777"  "58526"  "1739"   "2316"  
+## [113] "79658"  "8476"   "23365"  "4082"   "51199"  "5108"   "10928"  "7430"  
+## [121] "85464"  "983"    "22930"  "10160"  "11346"  "54509"  "1894"   "2035"  
+## [129] "51735"  "3835"   "84333"  "6780"   "396"    "6790"   "26271"  "51203" 
+## [137] "5829"   "9564"   "23607"  "11214"  "10013"  "22994"  "3996"   "23192" 
+## [145] "5116"   "7840"   "11133"  "667"    "22920"  "151987" "9411"   "9462"  
+## [153] "9133"   "80119"  "5922"   "4739"   "8243"   "81"     "5311"   "7461"  
+## [161] "998"    "10403"  "9874"   "9344"   "6904"   "832"    "1794"   "2017"  
+## [169] "10051"  "10565"  "7277"   "4001"   "10006"  "6093"   "55125"  "699"   
+## [177] "50628"  "64857"  "253260" "10018"  "1778"   "6624"   "8874"   "140735"
+## [185] "4643"   "274"    "4853"   "5981"   "10611"  "89941"  "8470"   "11135" 
+## [193] "7414"   "6249"   "23012"  "7531"   "9771"   "55722"  "1453"  
+## 
+## $HALLMARK_WNT_BETA_CATENIN_SIGNALING
+##  [1] "4609"  "1499"  "3714"  "4851"  "28514" "8313"  "5664"  "8321"  "4855" 
+## [10] "51176" "8312"  "85407" "81029" "8454"  "182"   "9794"  "2648"  "2770" 
+## [19] "7475"  "5727"  "9612"  "27121" "3066"  "22943" "6932"  "7471"  "8650" 
+## [28] "6868"  "1856"  "5467"  "23385" "10014" "894"   "10023" "1454"  "3516" 
+## [37] "8325"  "7157"  "6502"  "23493" "23462" "79885"
+## 
+## $HALLMARK_TGF_BETA_SIGNALING
+##  [1] "7046"  "4092"  "7040"  "64750" "57154" "659"   "6498"  "6497"  "90"   
+## [10] "56937" "9612"  "5054"  "3726"  "4086"  "4091"  "23645" "7050"  "5045" 
+## [19] "4088"  "2280"  "6885"  "657"   "1499"  "28996" "7071"  "650"   "2022" 
+## [28] "324"   "5494"  "331"   "999"   "3397"  "7044"  "1028"  "51592" "11031"
+## [37] "7082"  "6574"  "1025"  "3399"  "9241"  "51742" "3460"  "3398"  "5499" 
+## [46] "6711"  "25937" "8412"  "7057"  "2339"  "3065"  "7323"  "4053"  "387"
+

Looks like we have a list of gene sets with associated Entrez IDs.

+

In our gene expression data frame, expression_df we have Ensembl gene identifiers. So we will need to convert our Ensembl IDs into Entrez IDs for GSVA.

+
+
+

4.2.2 Gene identifier conversion

+

We’re going to convert our identifiers in expression_df to Entrez IDs, but you can, with the change of a single argument, use the same code to convert to many other types of identifiers!

+

The annotation package org.Hs.eg.db contains information for different identifiers (Carlson 2020). org.Hs.eg.db is specific to Homo sapiens – this is what the Hs in the package name is referencing.

+

We can see what types of IDs are available to us in an annotation package with keytypes().

+
keytypes(org.Hs.eg.db)
+
##  [1] "ACCNUM"       "ALIAS"        "ENSEMBL"      "ENSEMBLPROT"  "ENSEMBLTRANS"
+##  [6] "ENTREZID"     "ENZYME"       "EVIDENCE"     "EVIDENCEALL"  "GENENAME"    
+## [11] "GO"           "GOALL"        "IPI"          "MAP"          "OMIM"        
+## [16] "ONTOLOGY"     "ONTOLOGYALL"  "PATH"         "PFAM"         "PMID"        
+## [21] "PROSITE"      "REFSEQ"       "SYMBOL"       "UCSCKG"       "UNIGENE"     
+## [26] "UNIPROT"
+

Even though we’ll use this package to convert from Ensembl gene IDs (ENSEMBL) to Entrez IDs (ENTREZID), we could just as easily use it to convert from an Ensembl transcript ID (ENSEMBLTRANS) to gene symbols (SYMBOL).

+

Take a look at our other gene identifier conversion examples for examples with different species and gene ID types: the microarray example and the RNA-seq example.

+

The function we will use to map from Ensembl gene IDs to Entrez gene IDs is called mapIds().

+

Let’s create a data frame that shows the mapped Entrez IDs along with the gene expression values for the respective Ensembl IDs.

+
# First let's create a mapped data frame we can join to the gene expression values
+mapped_df <- data.frame(
+  "entrez_id" = mapIds(
+    org.Hs.eg.db, # Replace with annotation package for the organism relevant to your data
+    keys = expression_df$Gene,
+    column = "ENTREZID", # Replace with the type of gene identifiers you would like to map to
+    keytype = "ENSEMBL", # Replace with the type of gene identifiers in your data
+    multiVals = "first" # This will keep only the first mapped value for each Ensembl ID
+  )
+) %>%
+  # If an Ensembl gene identifier doesn't map to a Entrez gene identifier, drop that
+  # from the data frame
+  dplyr::filter(!is.na(entrez_id)) %>%
+  # Make an `Ensembl` column to store the row names
+  tibble::rownames_to_column("Ensembl") %>%
+  # Now let's join the rest of the expression data
+  dplyr::inner_join(expression_df, by = c("Ensembl" = "Gene")) %>%
+  # We won't be using Ensembl IDs moving forward, so we will drop this column
+  dplyr::select(-Ensembl)
+
## 'select()' returned 1:many mapping between keys and columns
+

This 1:many mapping between keys and columns message means that some Ensembl gene identifiers map to multiple Entrez IDs. In this case, it’s also possible that a Entrez ID will map to multiple Ensembl IDs. For the purpose of performing GSVA later in this notebook, we keep only the first mapped IDs. For more about how to explore this, take a look at our microarray gene ID conversion example.

+

Let’s see a preview of mapped_df.

+
head(mapped_df)
+
+ +
+

We will want to keep in mind that GSVA requires that data is in a matrix with the gene identifiers as row names. In order to successfully turn our data frame into a matrix, we will need to ensure that we do not have any duplicate gene identifiers.

+

Let’s check to see if we have any Entrez IDs that mapped to multiple Ensembl IDs.

+
any(duplicated(mapped_df$entrez_id))
+
## [1] TRUE
+

Looks like we do have duplicated Entrez IDs. Let’s find out which Entrez IDs have been duplicated.

+
dup_entrez_ids <- mapped_df %>%
+  dplyr::filter(duplicated(entrez_id)) %>%
+  dplyr::pull(entrez_id)
+
+dup_entrez_ids
+
## [1] "6013"   "148753"
+
+

4.2.2.1 Handling duplicate gene identifiers

+

As we mentioned earlier, we will not want any duplicate gene identifiers in our data frame when we convert it into a matrix in preparation for the GSVA steps later. GSVA is executed on a per sample basis so let’s keep the maximum expression value per sample associated with the duplicate Entrez gene identifiers. In other words, we will keep only the maximum expression value found across the duplicate Entrez gene identifier instances for each sample or column in this case.

+

Let’s take a look at the rows associated with the duplicated Entrez IDs and see how this will play out.

+
mapped_df %>%
+  dplyr::filter(entrez_id %in% dup_entrez_ids)
+
+ +
+

As an example using the strategy we described, for GSM187153’s data in the first column, -0.007355525 is larger than -0.136553967 so moving forward, Entrez gene 6013 will have -0.007355525 value and the -0.136553967 would be dropped from the dataset.

+

However, this is just one method of handling duplicate gene identifiers. See the Gene Set Enrichment Analysis (GSEA) User guide for more information on other expression values that can be used, like the median expression value for example (Broad Institute Team 2019).

+

Now, let’s implement our choose the max value method for all samples and Entrez IDs using tidyverse functions.

+
max_dup_df <- mapped_df %>%
+  # Filter to include only the rows associated with the duplicate Entrez gene identifiers
+  dplyr::filter(entrez_id %in% dup_entrez_ids) %>%
+  # Group by Entrez IDs
+  dplyr::group_by(entrez_id) %>%
+  # Get the maximum expression value using all values associated with each duplicate
+  # Entrez ID for each column or sample in this case
+  dplyr::summarize_all(max)
+
+max_dup_df
+
+ +
+

We can see GSM187153 now has the -0.007355525 value for Entrez ID 6013 like expected.

+

Looks like we were able to successfully get rid of the duplicate Entrez gene identifiers!

+

Now let’s combine our de-duplicated data with the rest of the mapped data!

+
filtered_mapped_df <- mapped_df %>%
+  # First let's get the data associated with the Entrez gene identifiers that aren't duplicated
+  dplyr::filter(!entrez_id %in% dup_entrez_ids) %>%
+  # Now let's bind the rows of the maximum expression data we stored in `max_dup_df`
+  dplyr::bind_rows(max_dup_df)
+

As mentioned earlier, we need a matrix for GSVA. Let’s now convert our data frame into a matrix and prepare our object for GSVA.

+
filtered_mapped_matrix <- filtered_mapped_df %>%
+  # We need to store our gene identifiers as row names
+  tibble::column_to_rownames("entrez_id") %>%
+  # Now we can convert our object into a matrix
+  as.matrix()
+

Note that if we had duplicate gene identifiers here, we would not be able to set them as row names.

+
+
+
+
+

4.3 GSVA - Microarray

+

Addressed in upcoming PR

+
+
+
+

5 Resources for further learning

+

Addressed in upcoming PR

+
+
+

6 Session info

+

At the end of every analysis, before saving your notebook, we recommend printing out your session info. This helps make your code more reproducible by recording what versions of software and packages you used to run this.

+
# Print session info
+sessioninfo::session_info()
+
## ─ Session info ───────────────────────────────────────────────────────────────
+##  setting  value                       
+##  version  R version 4.0.2 (2020-06-22)
+##  os       Ubuntu 20.04 LTS            
+##  system   x86_64, linux-gnu           
+##  ui       X11                         
+##  language (EN)                        
+##  collate  en_US.UTF-8                 
+##  ctype    en_US.UTF-8                 
+##  tz       Etc/UTC                     
+##  date     2020-11-20                  
+## 
+## ─ Packages ───────────────────────────────────────────────────────────────────
+##  package              * version  date       lib source        
+##  annotate               1.68.0   2020-10-27 [1] Bioconductor  
+##  AnnotationDbi        * 1.52.0   2020-10-27 [1] Bioconductor  
+##  assertthat             0.2.1    2019-03-21 [1] RSPM (R 4.0.0)
+##  backports              1.1.10   2020-09-15 [1] RSPM (R 4.0.2)
+##  Biobase              * 2.50.0   2020-10-27 [1] Bioconductor  
+##  BiocGenerics         * 0.36.0   2020-10-27 [1] Bioconductor  
+##  BiocParallel           1.24.1   2020-11-06 [1] Bioconductor  
+##  bit                    4.0.4    2020-08-04 [1] RSPM (R 4.0.2)
+##  bit64                  4.0.5    2020-08-30 [1] RSPM (R 4.0.2)
+##  bitops                 1.0-6    2013-08-17 [1] RSPM (R 4.0.0)
+##  blob                   1.2.1    2020-01-20 [1] RSPM (R 4.0.0)
+##  cli                    2.1.0    2020-10-12 [1] RSPM (R 4.0.2)
+##  coda                   0.19-4   2020-09-30 [1] RSPM (R 4.0.2)
+##  crayon                 1.3.4    2017-09-16 [1] RSPM (R 4.0.0)
+##  DBI                    1.1.0    2019-12-15 [1] RSPM (R 4.0.0)
+##  DelayedArray           0.16.0   2020-10-27 [1] Bioconductor  
+##  digest                 0.6.25   2020-02-23 [1] RSPM (R 4.0.0)
+##  dplyr                  1.0.2    2020-08-18 [1] RSPM (R 4.0.2)
+##  ellipsis               0.3.1    2020-05-15 [1] RSPM (R 4.0.0)
+##  emmeans                1.5.1    2020-09-18 [1] RSPM (R 4.0.2)
+##  estimability           1.3      2018-02-11 [1] RSPM (R 4.0.0)
+##  evaluate               0.14     2019-05-28 [1] RSPM (R 4.0.0)
+##  fansi                  0.4.1    2020-01-08 [1] RSPM (R 4.0.0)
+##  fftw                   1.0-6    2020-02-24 [1] RSPM (R 4.0.2)
+##  generics               0.0.2    2018-11-29 [1] RSPM (R 4.0.0)
+##  GenomeInfoDb           1.26.0   2020-10-27 [1] Bioconductor  
+##  GenomeInfoDbData       1.2.4    2020-11-18 [1] Bioconductor  
+##  GenomicRanges          1.42.0   2020-10-27 [1] Bioconductor  
+##  getopt                 1.20.3   2019-03-22 [1] RSPM (R 4.0.0)
+##  glue                   1.4.2    2020-08-27 [1] RSPM (R 4.0.2)
+##  graph                  1.68.0   2020-10-27 [1] Bioconductor  
+##  GSEABase               1.52.0   2020-10-27 [1] Bioconductor  
+##  GSVA                 * 1.38.0   2020-10-27 [1] Bioconductor  
+##  hms                    0.5.3    2020-01-08 [1] RSPM (R 4.0.0)
+##  htmltools              0.5.0    2020-06-16 [1] RSPM (R 4.0.1)
+##  httr                   1.4.2    2020-07-20 [1] RSPM (R 4.0.2)
+##  IRanges              * 2.24.0   2020-10-27 [1] Bioconductor  
+##  jsonlite               1.7.1    2020-09-07 [1] RSPM (R 4.0.2)
+##  knitr                  1.30     2020-09-22 [1] RSPM (R 4.0.2)
+##  lattice                0.20-41  2020-04-02 [2] CRAN (R 4.0.2)
+##  lifecycle              0.2.0    2020-03-06 [1] RSPM (R 4.0.0)
+##  limma                * 3.46.0   2020-10-27 [1] Bioconductor  
+##  magrittr             * 1.5      2014-11-22 [1] RSPM (R 4.0.0)
+##  Matrix                 1.2-18   2019-11-27 [2] CRAN (R 4.0.2)
+##  MatrixGenerics         1.2.0    2020-10-27 [1] Bioconductor  
+##  matrixStats            0.57.0   2020-09-25 [1] RSPM (R 4.0.2)
+##  memoise                1.1.0    2017-04-21 [1] RSPM (R 4.0.0)
+##  mvtnorm                1.1-1    2020-06-09 [1] RSPM (R 4.0.0)
+##  nlme                   3.1-148  2020-05-24 [2] CRAN (R 4.0.2)
+##  optparse             * 1.6.6    2020-04-16 [1] RSPM (R 4.0.0)
+##  org.Hs.eg.db         * 3.12.0   2020-11-18 [1] Bioconductor  
+##  pillar                 1.4.6    2020-07-10 [1] RSPM (R 4.0.2)
+##  pkgconfig              2.0.3    2019-09-22 [1] RSPM (R 4.0.0)
+##  ps                     1.4.0    2020-10-07 [1] RSPM (R 4.0.2)
+##  purrr                  0.3.4    2020-04-17 [1] RSPM (R 4.0.0)
+##  qusage               * 2.24.0   2020-10-27 [1] Bioconductor  
+##  R.cache                0.14.0   2019-12-06 [1] RSPM (R 4.0.0)
+##  R.methodsS3            1.8.1    2020-08-26 [1] RSPM (R 4.0.2)
+##  R.oo                   1.24.0   2020-08-26 [1] RSPM (R 4.0.2)
+##  R.utils                2.10.1   2020-08-26 [1] RSPM (R 4.0.2)
+##  R6                     2.4.1    2019-11-12 [1] RSPM (R 4.0.0)
+##  Rcpp                   1.0.5    2020-07-06 [1] RSPM (R 4.0.2)
+##  RCurl                  1.98-1.2 2020-04-18 [1] RSPM (R 4.0.0)
+##  readr                  1.4.0    2020-10-05 [1] RSPM (R 4.0.2)
+##  rematch2               2.1.2    2020-05-01 [1] RSPM (R 4.0.0)
+##  rlang                  0.4.8    2020-10-08 [1] RSPM (R 4.0.2)
+##  rmarkdown              2.4      2020-09-30 [1] RSPM (R 4.0.2)
+##  RSQLite                2.2.1    2020-09-30 [1] RSPM (R 4.0.2)
+##  rstudioapi             0.11     2020-02-07 [1] RSPM (R 4.0.0)
+##  S4Vectors            * 0.28.0   2020-10-27 [1] Bioconductor  
+##  sessioninfo            1.1.1    2018-11-05 [1] RSPM (R 4.0.0)
+##  stringi                1.5.3    2020-09-09 [1] RSPM (R 4.0.2)
+##  stringr                1.4.0    2019-02-10 [1] RSPM (R 4.0.0)
+##  styler                 1.3.2    2020-02-23 [1] RSPM (R 4.0.0)
+##  SummarizedExperiment   1.20.0   2020-10-27 [1] Bioconductor  
+##  tibble                 3.0.4    2020-10-12 [1] RSPM (R 4.0.2)
+##  tidyselect             1.1.0    2020-05-11 [1] RSPM (R 4.0.0)
+##  vctrs                  0.3.4    2020-08-29 [1] RSPM (R 4.0.2)
+##  withr                  2.3.0    2020-09-22 [1] RSPM (R 4.0.2)
+##  xfun                   0.18     2020-09-29 [1] RSPM (R 4.0.2)
+##  XML                    3.99-0.5 2020-07-23 [1] RSPM (R 4.0.2)
+##  xtable                 1.8-4    2019-04-21 [1] RSPM (R 4.0.0)
+##  XVector                0.30.0   2020-10-27 [1] Bioconductor  
+##  yaml                   2.2.1    2020-02-01 [1] RSPM (R 4.0.0)
+##  zlibbioc               1.36.0   2020-10-27 [1] Bioconductor  
+## 
+## [1] /usr/local/lib/R/site-library
+## [2] /usr/local/lib/R/library
+
+
+

References

+
+
+

Broad Institute Team, 2019 Gene set enrichment analysis (gsea) user guide. https://www.gsea-msigdb.org/gsea/doc/GSEAUserGuideFrame.html

+
+
+

Carlson M., 2020 org.Hs.eg.db: Genome wide annotation for human. http://bioconductor.org/packages/release/data/annotation/html/org.Hs.eg.db.html

+
+
+

Dolgalev I., 2020 Msigdbr: MSigDB gene sets for multiple organisms in a tidy data format. https://cran.r-project.org/web/packages/msigdbr/index.html

+
+
+

Hänzelmann S., R. Castelo, and J. Guinney, 2013a Biases in Illumina transcriptome sequencing caused by random hexamer priming. BMC Bioinformatics 14. https://doi.org/10.1186/1471-2105-14-7

+
+
+

Hänzelmann S., R. Castelo, and J. Guinney, 2013b GSVA. https://github.com/rcastelo/GSVA/blob/master/man/gsva.Rd

+
+
+

Meng H., G. Yaari, C. R. Bolen, S. Avey, and S. H. Kleinstein, 2019 Gene set meta-analysis with quantitative set analysis for gene expression (qusage). PLoS Computat Biol. 15: e1006899. https://doi.org/10.1371/journal.pcbi.1006899

+
+
+
+ + + + +
+
+ +
+ + + + + + + + + + + + + + + + diff --git a/Snakefile b/Snakefile index 6551e2c0..e9c26d36 100644 --- a/Snakefile +++ b/Snakefile @@ -10,6 +10,7 @@ rule target: "02-microarray/gene-id-annotation_microarray_01_ensembl.html", "02-microarray/pathway-analysis_microarray_01_ora.html", "02-microarray/pathway-analysis_microarray_02_gsea.html", + "02-microarray/pathway-analysis_microarray_03_gsva.html", "02-microarray/ortholog-mapping_microarray_01_ensembl.html", "03-rnaseq/00-intro-to-rnaseq.html", "03-rnaseq/clustering_rnaseq_01_heatmap.html", diff --git a/components/_navbar.html b/components/_navbar.html index 2b5fd905..fe4358c1 100644 --- a/components/_navbar.html +++ b/components/_navbar.html @@ -34,6 +34,7 @@
  • Dimension Reduction - UMAP
  • Pathway Analysis - ORA
  • Pathway Analysis - GSEA
  • +
  • Pathway Analysis - GSVA
  • Ensembl Gene ID Annotation
  • Ortholog Mapping
  • diff --git a/components/dictionary.txt b/components/dictionary.txt index f70d106a..2290522d 100644 --- a/components/dictionary.txt +++ b/components/dictionary.txt @@ -17,6 +17,7 @@ Brems CCDL CCDL's cDNA +centric cheatsheet cheatsheets ChIP @@ -31,6 +32,7 @@ cytosolic Danio dataset dataset's +de decitabine DESeq DESeq2 @@ -61,10 +63,12 @@ Genenames generalizable ggplot GitHub +glioblastoma glioma GC GSE GSEA +GSVA HCOP hexamer HGNC diff --git a/components/references.bib b/components/references.bib index e68ead75..218b44c9 100644 --- a/components/references.bib +++ b/components/references.bib @@ -215,6 +215,14 @@ @website{GSEA-broad-institute url = {https://www.gsea-msigdb.org/gsea/index.jsp} } +@website{GSEA-user-guide, + title = {Gene Set Enrichment Analysis (GSEA) User Guide}, + author = {{Broad Institute Team}}, + month = {November}, + year = {2019}, + url = {https://www.gsea-msigdb.org/gsea/doc/GSEAUserGuideFrame.html} +} + @article{Gu2016, title = {Complex heatmaps reveal patterns and correlations in multidimensional genomic data}, author = {Zuguang Gu and Roland Eils and Matthias Schlesner}, @@ -238,6 +246,19 @@ @website{Hadfield2016 year = {2016}, url = {https://bitesizebio.com/13542/what-everyone-should-know-about-rna-seq/} } + +@article{Meng2019, + author = {Hailong Meng and Gur Yaari and Christopher R. Bolen and Stefan Avey and Steven H. Kleinstein}, + title = {Gene set meta-analysis with Quantitative Set Analysis for Gene Expression (QuSAGE)}, + journal = {PLoS Computat Biol.}, + year = {2019}, + volume = {15}, + number = {4}, + pages = {e1006899}, + month = {April}, + doi = {10.1371/journal.pcbi.1006899}, + url = {https://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1006899} +} @article{Hansen2010, author = {Hansen, K. D. and Brenner, S. E. and Dudoit, S. }, @@ -252,6 +273,24 @@ @article{Hansen2010 url = {https://pubmed.ncbi.nlm.nih.gov/20395217/} } +@article{Hanzelmann2013, + author = {Sonja Hänzelmann and Robert Castelo and Justin Guinney}, + title = {Biases in {Illumina} transcriptome sequencing caused by random hexamer priming}, + journal = {BMC Bioinformatics}, + year = {2013}, + volume = {14}, + number = {7}, + doi = {10.1186/1471-2105-14-7}, + url = {https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-14-7} +} + +@website{Hanzelmann-github, + title = {GSVA}, + author = {Sonja Hänzelmann and Robert Castelo and Justin Guinney}, + year = {2013}, + url = {https://github.com/rcastelo/GSVA/blob/master/man/gsva.Rd} +} + @manual{Hastie2020, title = {impute: Imputation for microarray data}, author = {Trevor Hastie and Robert Tibshirani and Balasubramanian Narasimhan and Gilbert Chu}, @@ -467,6 +506,13 @@ @website{Love2020 url = {https://bioconductor.org/packages/release/bioc/vignettes/DESeq2/inst/doc/DESeq2.html} } +@website{Malhotra2018, + title = {Decoding Gene Set Variation Analysis}, + author = {Saksham Malhotra}, + year = {2018}, + url = {https://towardsdatascience.com/decoding-gene-set-variation-analysis-8193a0cfda3} +} + @article{Mantione2014, author = {Mantione, K. J. and Kream, R. M. and Kuzelova, H. and Ptacek, R. and Raboch, J. and Samuel, J. M. and Stefano, G. B. }, title = {Comparing bioinformatic gene expression profiling methods: microarray and {RNA-Seq}}, diff --git a/docker/Dockerfile b/docker/Dockerfile index d4bd6146..17817682 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -63,7 +63,9 @@ RUN Rscript -e "options(warn = 2); BiocManager::install( \ 'marray', \ 'msigdbr', \ 'org.Mm.eg.db', \ - 'org.Dr.eg.db'), \ + 'org.Dr.eg.db', \ + 'org.Hs.eg.db', \ + 'qusage'), \ update = FALSE)" # Installs packages needed for plottings From 2fc9de21b988a3f0caad1b1f03bce49d3c1dcc2d Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Mon, 23 Nov 2020 17:20:22 -0500 Subject: [PATCH 44/50] WGCNA Part 3: DE and heatmaps (#363) * Put in basic changes: navbar, dict, snakefile, Rmd * More polishing and info and refs * Update file paths * Bring back docker changes * Add to dictionary * Add a couple refs * Add next steps * Add some polishing and refs * Address the straightforward items from cbethell 's review * Incorporate jashapiro review from #358 * Style Rmds * Bring over part1 changes and re-render * Add last set of steps * Push this partcular plot version in case we wanna come back to it * Commit this multiple module pheatmap in case I want to return to it * ComplexHeatmap is mostly wrangled * It's working! * Save to PDFs * Fix color function and re-render * Add outlier thing * Revert "Add outlier thing" This reverts commit 8b9d57ce13ff2b6b6c5ddbb0169a794f6bbd36de. * Add ref for ComplexHeatmap * Incorporate jashapiro review and rerender * Remove standardize_genes option * Wrap up those last few typo things Co-authored-by: GitHub Actions --- .../network-analysis_rnaseq_01_wgcna.Rmd | 288 +++++++++++- .../network-analysis_rnaseq_01_wgcna.html | 419 ++++++++++++++---- 2 files changed, 608 insertions(+), 99 deletions(-) diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd index c46b3872..6553f6e2 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd @@ -198,7 +198,7 @@ We will be using `DESeq2` to normalize and transform our RNA-seq data before run Of course, we will need the `WGCNA` package [@Langfelder2008]. But `WGCNA` also requires a package called `impute` that it sometimes has trouble installing so we recommend installing that first [@Hastie2020]. -Lastly, we will be creating a `sina` plot which we will need a `ggplot2` companion package for, called `ggforce`. +For plotting purposes will be creating a `sina` plot and heatmaps which we will need a `ggplot2` companion package for, called `ggforce` as well as the `ComplexHeatmap` package [@Gu2020]. ```{r} if (!("DESeq2" %in% installed.packages())) { @@ -220,6 +220,11 @@ if (!("ggforce" %in% installed.packages())) { # Install this package if it isn't installed yet install.packages("ggforce") } + +if (!("ComplexHeatmap" %in% installed.packages())) { + # Install this package if it isn't installed yet + install.packages("ComplexHeatmap") +} ``` Attach some of the packages we need for this analysis. @@ -286,6 +291,23 @@ df <- round(df) %>% dplyr::filter(rowSums(.) >= 50) ``` +Another thing we need to do is make sure our main experimental group label is set up. +In this case `refinebio_treatment` has two groups: `pre-adt` and `post-adt`. +To keep these two treatments in logical (rather than alphabetical) order, we will convert this to a factor with `pre-adt` as the first level. + +```{r} +metadata <- metadata %>% + dplyr::mutate(refinebio_treatment = factor(refinebio_treatment, + levels = c("pre-adt", "post-adt") + )) +``` + +Let's double check that our factor set up is right. + +```{r} +levels(metadata$refinebio_treatment) +``` + ## Create a DESeqDataset We will be using the `DESeq2` package for [normalizing and transforming our data](https://alexslemonade.github.io/refinebio-examples/03-rnaseq/00-intro-to-rnaseq.html#deseq2-transformation-methods), which requires us to format our data into a `DESeqDataSet` object. @@ -420,13 +442,275 @@ readr::write_rds(bwnet, ) ``` -_Next sections addressed in upcoming PR_ +## Explore our WGCNA results + +The `bwnet` object has many parts, storing a lot of information. +We can pull out the parts we are most interested in and may want to use use for plotting. + +In `bwnet` we have a data frame of eigengene module data for each sample in the `MEs` slot. +These represent the collapsed, combined, and normalized expression of the genes that make up each module. + +```{r} +module_eigengenes <- bwnet$MEs + +# Print out a preview +head(module_eigengenes) +``` + +## Which modules have biggest differences across treatment groups? + +We can also see if our eigengenes relate to our metadata labels. +First we double check that our samples are still in order. + +```{r} +all.equal(metadata$refinebio_accession_code, rownames(module_eigengenes)) +``` + +```{r} +# Create the design matrix from the refinebio_treatment variable +des_mat <- model.matrix(~ metadata$refinebio_treatment) +``` + +Run linear model on each module. +Limma wants our tests to be per row, so we also need to transpose so the eigengenes are rows + +```{r} +# lmFit() needs a transposed version of the matrix +fit <- limma::lmFit(t(module_eigengenes), design = des_mat) + +# Apply empirical Bayes to smooth standard errors +fit <- limma::eBayes(fit) +``` + +Apply multiple testing correction and obtain stats in a data frame. + +```{r} +# Apply multiple testing correction and obtain stats +stats_df <- limma::topTable(fit, number = ncol(module_eigengenes)) %>% + tibble::rownames_to_column("module") +``` + +Let's take a look at the results. +They are sorted with the most significant results at the top. + +```{r} +head(stats_df) +``` + +Module 52 seems to be the most differentially expressed across `refinebio_treatment` groups. +Now we can do some investigation into this module. + +## Let's make plot of module 52 + +As a sanity check, let's use `ggplot` to see what module 52's eigengene looks like between treatment groups. + +First we need to set up the module eigengene for this module with the sample metadata labels we need. + +```{r} +module_52_df <- module_eigengenes %>% + tibble::rownames_to_column("accession_code") %>% + # Here we are performing an inner join with a subset of metadata + dplyr::inner_join(metadata %>% + dplyr::select(refinebio_accession_code, refinebio_treatment), + by = c("accession_code" = "refinebio_accession_code") + ) +``` + +Now we are ready for plotting. + +```{r} +ggplot( + module_52_df, + aes( + x = refinebio_treatment, + y = ME52, + color = refinebio_treatment + ) +) + + ggforce::geom_sina() + + theme_classic() +``` + +This makes sense! +Looks like module 52 has elevated expression post treatment. + +## What genes are a part of module 52? + +If you want to know which of your genes make up a modules, you can look at the `$colors` slot. +This is a named list which associates the genes with the module they are a part of. +We can turn this into a data frame for handy use. + +```{r} +gene_module_key <- tibble::enframe(bwnet$colors, name = "gene", value = "module") %>% + # Let's add the `ME` part so its more clear what these numbers are and it matches elsewhere + dplyr::mutate(module = paste0("ME", module)) +``` + +Now we can find what genes are a part of module 52. + +```{r} +gene_module_key %>% + dplyr::filter(module == "ME52") +``` + +Let's save this gene to module key to a TSV file for future use. + +```{r} +readr::write_tsv(gene_module_key, + file = file.path("results", "SRP133573_wgcna_gene_to_module.tsv") +) +``` + +## Make a custom heatmap function + +We will make a heatmap that summarizes our differentially expressed module. +Because we will make a couple of these, it makes sense to make a custom function for making this heatmap. + +```{r} +make_module_heatmap <- function(module_name, + expression_mat = normalized_counts, + metadata_df = metadata, + gene_module_key_df = gene_module_key, + module_eigengenes_df = module_eigengenes) { + # Create a summary heatmap of a given module. + # + # Args: + # module_name: a character indicating what module should be plotted, e.g. "ME52" + # expression_mat: The full gene expression matrix. Default is `normalized_counts`. + # metadata_df: a data frame with refinebio_accession_code and refinebio_treatment + # as columns. Default is `metadata`. + # gene_module_key: a data.frame indicating what genes are a part of what modules. Default is `gene_module_key`. + # module_eigengenes: a sample x eigengene data.frame with samples as rownames. Default is `module_eigengenes`. + # + # Returns: + # A heatmap of expression matrix for a module's genes, with a barplot of the + # eigengene expression for that module. + + # Set up the module eigengene with its refinebio_accession_code + module_eigengene <- module_eigengenes_df %>% + dplyr::select(module_name) %>% + tibble::rownames_to_column("refinebio_accession_code") + + # Set up column annotation from metadata + col_annot_df <- metadata_df %>% + # Only select the treatment and sample ID columns + dplyr::select(refinebio_accession_code, refinebio_treatment) %>% + # Add on the eigengene expression by joining with sample IDs + dplyr::inner_join(module_eigengene, by = "refinebio_accession_code") %>% + # Arrange by treatment + dplyr::arrange(refinebio_treatment, refinebio_accession_code) %>% + # Store sample + tibble::column_to_rownames("refinebio_accession_code") + + # Create the ComplexHeatmap column annotation object + col_annot <- ComplexHeatmap::HeatmapAnnotation( + # Supply treatment labels + refinebio_treatment = col_annot_df$refinebio_treatment, + # Add annotation barplot + module_eigengene = ComplexHeatmap::anno_barplot(dplyr::select(col_annot_df, module_name)), + # Pick colors for each experimental group in refinebio_treatment + col = list(refinebio_treatment = c("post-adt" = "#f1a340", "pre-adt" = "#998ec3")) + ) + + # Get a vector of the Ensembl gene IDs that correspond to this module + module_genes <- gene_module_key_df %>% + dplyr::filter(module == module_name) %>% + dplyr::pull(gene) + + # Set up the gene expression data frame + mod_mat <- expression_mat %>% + t() %>% + as.data.frame() %>% + # Only keep genes from this module + dplyr::filter(rownames(.) %in% module_genes) %>% + # Order the samples to match col_annot_df + dplyr::select(rownames(col_annot_df)) %>% + # Data needs to be a matrix + as.matrix() + + # Normalize the gene expression values + mod_mat <- mod_mat %>% + # Scale can work on matrices, but it does it by column so we will need to + # transpose first + t() %>% + scale() %>% + # And now we need to transpose back + t() + + # Create a color function based on standardized scale + color_func <- circlize::colorRamp2( + c(-2, 0, 2), + c("#67a9cf", "#f7f7f7", "#ef8a62") + ) + + # Plot on a heatmap + heatmap <- ComplexHeatmap::Heatmap(mod_mat, + name = module_name, + # Supply color function + col = color_func, + # Supply column annotation + bottom_annotation = col_annot, + # We don't want to cluster samples + cluster_columns = FALSE, + # We don't need to show sample or gene labels + show_row_names = FALSE, + show_column_names = FALSE + ) + + # Return heatmap + return(heatmap) +} +``` + +## Make module heatmaps + +Let's try out the custom heatmap function with module 52 (our most differentially expressed module). + +```{r} +mod_52_heatmap <- make_module_heatmap(module_name = "ME52") + +# Print out the plot +mod_52_heatmap +``` + +From the barplot portion of our plot, we can see `post-adt` samples have higher values for this eigengene for module 52. +In the heatmap portion, we can see how the individual genes that make up module 52 have more extreme values (very high or very low) in the `post-adt` samples. + +We can save this plot to PDF. + +```{r} +pdf(file.path("results", "SRP133573_module_52_heatmap.pdf")) +mod_52_heatmap +dev.off() +``` + +For comparison, let's try out the custom heatmap function with a different, _not_ differentially expressed module. + +```{r} +mod_10_heatmap <- make_module_heatmap(module_name = "ME10") + +# Print out the plot +mod_10_heatmap +``` + +In this non-significant module's heatmap, there's not a particularly strong pattern between pre and post ADT samples. +In general the expression of genes in module 10 does not vary much between groups, staying near the overall mean. +There are a few samples and some genes that show higher expression, but it is not surprising this does not results in a significant overall difference between the groups. + +Save this plot also. + +```{r} +pdf(file.path("results", "SRP133573_module_10_heatmap.pdf")) +mod_10_heatmap +dev.off() +``` # Resources for further learning - [WGCNA FAQ page](https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/faq.html) [@Langfelder2016]. - [WGCNA tutorial](https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/Tutorials/) [@Langfelder2016]. - [WGCNA paper](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-9-559) [@Langfelder2008]. +- [ComplexHeatmap's tutorial guide](https://jokergoo.github.io/ComplexHeatmap-reference/book/) for more info on how to tweak the heatmaps [@Gu2020]. # Session info diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html index ceff7f51..b81a41c6 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html @@ -3900,7 +3900,7 @@

    4.1 Install libraries

    See our Getting Started page with instructions for package installation for a list of the other software you will need, as well as more tips and resources.

    We will be using DESeq2 to normalize and transform our RNA-seq data before running WGCNA, so we will need to install that (Love et al. 2014).

    Of course, we will need the WGCNA package (Langfelder and Horvath 2008). But WGCNA also requires a package called impute that it sometimes has trouble installing so we recommend installing that first (Hastie et al. 2020).

    -

    Lastly, we will be creating a sina plot which we will need a ggplot2 companion package for, called ggforce.

    +

    For plotting purposes will be creating a sina plot and heatmaps which we will need a ggplot2 companion package for, called ggforce as well as the ComplexHeatmap package (Gu 2020).

    if (!("DESeq2" %in% installed.packages())) {
       # Install this package if it isn't installed yet
       BiocManager::install("DESeq2", update = FALSE)
    @@ -3919,7 +3919,12 @@ 

    4.1 Install libraries

    if (!("ggforce" %in% installed.packages())) { # Install this package if it isn't installed yet install.packages("ggforce") -}
    +} + +if (!("ComplexHeatmap" %in% installed.packages())) { + # Install this package if it isn't installed yet + install.packages("ComplexHeatmap") +}

    Attach some of the packages we need for this analysis.

    # Attach the DESeq2 library
     library(DESeq2)
    @@ -4023,7 +4028,7 @@

    4.2 Import and set up data

    # Read in metadata TSV file
     metadata <- readr::read_tsv(metadata_file)
    ## 
    -## ── Column specification ───────────────────────────────────────────────────────────────────────────
    +## ── Column specification ──────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_character(),
     ##   refinebio_age = col_logical(),
    @@ -4043,7 +4048,7 @@ 

    4.2 Import and set up data

    # Here we are going to store the gene IDs as rownames so that we can have a numeric matrix to perform calculations on later tibble::column_to_rownames("Gene")
    ## 
    -## ── Column specification ───────────────────────────────────────────────────────────────────────────
    +## ── Column specification ──────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_double(),
     ##   Gene = col_character()
    @@ -4068,42 +4073,50 @@ 

    4.2.1 Prepare data for DESe as.data.frame() %>% # Only keep rows that have total counts above the cutoff dplyr::filter(rowSums(.) >= 50)

    +

    Another thing we need to do is make sure our main experimental group label is set up. In this case refinebio_treatment has two groups: pre-adt and post-adt. To keep these two treatments in logical (rather than alphabetical) order, we will convert this to a factor with pre-adt as the first level.

    +
    metadata <- metadata %>%
    +  dplyr::mutate(refinebio_treatment = factor(refinebio_treatment,
    +    levels = c("pre-adt", "post-adt")
    +  ))
    +

    Let’s double check that our factor set up is right.

    +
    levels(metadata$refinebio_treatment)
    +
    ## [1] "pre-adt"  "post-adt"

    4.3 Create a DESeqDataset

    We will be using the DESeq2 package for normalizing and transforming our data, which requires us to format our data into a DESeqDataSet object. We turn the data frame (or matrix) into a DESeqDataSet object and specify which variable labels our experimental groups using the design argument (Love et al. 2014). In this chunk of code, we will not provide a specific model to the design argument because we are not performing a differential expression analysis.

    -
    # Create a `DESeqDataSet` object
    -dds <- DESeqDataSetFromMatrix(
    -  countData = df, # Our prepped data frame with counts
    -  colData = metadata, # Data frame with annotation for our samples
    -  design = ~1 # Here we are not specifying a model
    -)
    +
    # Create a `DESeqDataSet` object
    +dds <- DESeqDataSetFromMatrix(
    +  countData = df, # Our prepped data frame with counts
    +  colData = metadata, # Data frame with annotation for our samples
    +  design = ~1 # Here we are not specifying a model
    +)
    ## converting counts to integer mode

    4.4 Perform DESeq2 normalization and transformation

    We often suggest normalizing and transforming your data for various applications and in this instance WGCNA’s authors suggest using variance stabilizing transformation before running WGCNA.
    We are going to use the vst() function from the DESeq2 package to normalize and transform the data. For more information about these transformation methods, see here.

    -
    # Normalize and transform the data in the `DESeqDataSet` object using the `vst()`
    -# function from the `DESEq2` R package
    -dds_norm <- vst(dds)
    +
    # Normalize and transform the data in the `DESeqDataSet` object using the `vst()`
    +# function from the `DESEq2` R package
    +dds_norm <- vst(dds)

    4.5 Format normalized data for WGCNA

    Extract the normalized counts to a matrix and transpose it so we can pass it to WGCNA.

    -
    # Retrieve the normalized data from the `DESeqDataSet`
    -normalized_counts <- assay(dds_norm) %>%
    -  t() # Transpose this data
    +
    # Retrieve the normalized data from the `DESeqDataSet`
    +normalized_counts <- assay(dds_norm) %>%
    +  t() # Transpose this data

    4.6 Determine parameters for WGCNA

    To identify which genes are in the same modules, WGCNA first creates a weighted network to define which genes are near each other. The measure of “adjacency” it uses is based on the correlation matrix, but requires the definition of a threshold value, which in turn depends on a “power” parameter that defines the exponent used when transforming the correlation values. The choice of power parameter will affect the number of modules identified, and the WGCNA modules provides the pickSoftThreshold() function to help identify good choices for this parameter.

    -
    sft <- pickSoftThreshold(normalized_counts,
    -  dataIsExpr = TRUE,
    -  corFnc = cor,
    -  networkType = "signed"
    -)
    +
    sft <- pickSoftThreshold(normalized_counts,
    +  dataIsExpr = TRUE,
    +  corFnc = cor,
    +  networkType = "signed"
    +)
    ## Warning: executing %dopar% sequentially: no parallel backend registered
    ##    Power SFT.R.sq  slope truncated.R.sq mean.k. median.k. max.k.
     ## 1      1  0.58200 12.200          0.957 13500.0   13600.0  15500
    @@ -4122,39 +4135,29 @@ 

    4.6 Determine parameters for WGCN ## 14 18 0.83800 -2.360 0.985 28.6 18.9 227 ## 15 20 0.84500 -2.350 0.987 18.5 11.2 167

    This sft object has a lot of information, we will want to plot some of it to figure out what our power soft-threshold should be. We have to first calculate a measure of the model fit, the signed \(R^2\), and make that a new variable.

    -
    sft_df <- data.frame(sft$fitIndices) %>%
    -  dplyr::mutate(model_fit = -sign(slope) * SFT.R.sq)
    +
    sft_df <- data.frame(sft$fitIndices) %>%
    +  dplyr::mutate(model_fit = -sign(slope) * SFT.R.sq)

    Now, let’s plot the model fitting by the power soft threshold so we can decide on a soft-threshold for power.

    -
    ggplot(sft_df, aes(x = Power, y = model_fit, label = Power)) +
    -  # Plot the points
    -  geom_point() +
    -  # We'll put the Power labels slightly above the data points
    -  geom_label(nudge_y = 0.1) +
    -  # We will plot what WGCNA recommends as an R^2 cutoff
    -  geom_hline(yintercept = 0.80, col = "red") +
    -  # Just in case our values are low, we want to make sure we can still see the 0.80 level
    -  ylim(c(min(sft_df$model_fit), 1)) +
    -  # We can add more sensible labels for our axis
    -  xlab("Soft Threshold (power)") +
    -  ylab("Scale Free Topology Model Fit, signed R^2") +
    -  ggtitle("Scale independence") +
    -  # This adds some nicer aesthetics to our plot
    -  theme_classic()
    -

    +
    ggplot(sft_df, aes(x = Power, y = model_fit, label = Power)) +
    +  # Plot the points
    +  geom_point() +
    +  # We'll put the Power labels slightly above the data points
    +  geom_text(nudge_y = 0.1) +
    +  # We will plot what WGCNA recommends as an R^2 cutoff
    +  geom_hline(yintercept = 0.80, col = "red") +
    +  # Just in case our values are low, we want to make sure we can still see the 0.80 level
    +  ylim(c(min(sft_df$model_fit), 1)) +
    +  # We can add more sensible labels for our axis
    +  xlab("Soft Threshold (power)") +
    +  ylab("Scale Free Topology Model Fit, signed R^2") +
    +  ggtitle("Scale independence") +
    +  # This adds some nicer aesthetics to our plot
    +  theme_classic()
    +

    Using this plot we can decide on a power parameter. WGCNA’s authors recommend using a power that has an signed \(R^2\) above 0.80, otherwise they warn your results may be too noisy to be meaningful.

    If you have multiple power values with signed \(R^2\) above 0.80, then picking the one at an inflection point, in other words where the \(R^2\) values seem to have reached their saturation (Zhang and Horvath 2005). You want to a power that gives you a big enough \(R^2\) but is not excessively large.

    So using the plot above, going with a power soft-threshold of 16!

    -

    If you find you have all very low \(R^2\) values this may be because there are too many genes with low values that are cluttering up the calculations. You can try returning to gene filtering step and choosing a more stringent cutoff (you’ll then need to re-run the transformation and subsequent steps to remake this plot to see if that helped).

    -
    sft_df %>%
    -  ggplot() +
    -  geom_label(aes(x = Power, y = max.k.), label = sft_df$Power) +
    -  # We can add more sensible labels for our axis
    -  xlab("Soft Threshold (power)") +
    -  ylab("Scale Free Topology Model Fit, signed R^2") +
    -  ggtitle("Scale independence") +
    -  # This adds some nicer aesthetics to our plot
    -  theme_classic()
    -

    +

    If you find you have all very low \(R^2\) values this may be because there are too many genes with low expression values that are cluttering up the calculations. You can try returning to gene filtering step and choosing a more stringent cutoff (you’ll then need to re-run the transformation and subsequent steps to remake this plot to see if that helped).

    4.7 Run WGCNA!

    @@ -4165,24 +4168,237 @@

    4.7 Run WGCNA!

    • If the reader has access to a large workstation with more than 4 GB of memory, the parameter maxBlockSize can be increased. A 16GB workstation should handle up to 20000 probes; a 32GB workstation should handle perhaps 30000. A 4GB standard desktop or a laptop may handle up to 8000-10000 probes, depending on operating system and other running programs.

    (Langfelder and Horvath 2016)

    -
    bwnet <- blockwiseModules(normalized_counts,
    -  maxBlockSize = 5000, # What size chunks (how many genes) the calculations should be run in
    -  TOMType = "signed", # topological overlap matrix
    -  power = 16, # soft threshold for network construction
    -  numericLabels = TRUE, # Let's use numbers instead of colors for module labels
    -  randomSeed = 1234, # there's some randomness associated with this calculation
    -  # so we should set a seed
    -)
    +
    bwnet <- blockwiseModules(normalized_counts,
    +  maxBlockSize = 5000, # What size chunks (how many genes) the calculations should be run in
    +  TOMType = "signed", # topological overlap matrix
    +  power = 16, # soft threshold for network construction
    +  numericLabels = TRUE, # Let's use numbers instead of colors for module labels
    +  randomSeed = 1234, # there's some randomness associated with this calculation
    +  # so we should set a seed
    +)

    The TOMtype argument specifies what kind of topological overlap matrix (TOM) should be used to make gene modules. You can safely assume for most situations a signed network represents what you want – we want WGCNA to pay attention to directionality. However if you suspect you may benefit from an unsigned network, where positive/negative is ignored see this article to help you figure that out (Langfelder 2018).

    There are a lot of other settings you can tweak – look at ?blockwiseModules help page as well as the WGCNA tutorial (Langfelder and Horvath 2016).

    4.8 Write main WGCNA results object to file

    We will save our whole results object to an RDS file in case we want to return to our original WGCNA results.

    -
    readr::write_rds(bwnet,
    -  file = file.path("results", "SRP133573_wgcna_results.RDS")
    -)
    -

    Next sections addressed in upcoming PR

    +
    readr::write_rds(bwnet,
    +  file = file.path("results", "SRP133573_wgcna_results.RDS")
    +)
    +
    +
    +

    4.9 Explore our WGCNA results

    +

    The bwnet object has many parts, storing a lot of information. We can pull out the parts we are most interested in and may want to use use for plotting.

    +

    In bwnet we have a data frame of eigengene module data for each sample in the MEs slot. These represent the collapsed, combined, and normalized expression of the genes that make up each module.

    +
    module_eigengenes <- bwnet$MEs
    +
    +# Print out a preview
    +head(module_eigengenes)
    +
    + +
    +
    +
    +

    4.10 Which modules have biggest differences across treatment groups?

    +

    We can also see if our eigengenes relate to our metadata labels. First we double check that our samples are still in order.

    +
    all.equal(metadata$refinebio_accession_code, rownames(module_eigengenes))
    +
    ## [1] TRUE
    +
    # Create the design matrix from the refinebio_treatment variable
    +des_mat <- model.matrix(~ metadata$refinebio_treatment)
    +

    Run linear model on each module. Limma wants our tests to be per row, so we also need to transpose so the eigengenes are rows

    +
    # lmFit() needs a transposed version of the matrix
    +fit <- limma::lmFit(t(module_eigengenes), design = des_mat)
    +
    +# Apply empirical Bayes to smooth standard errors
    +fit <- limma::eBayes(fit)
    +

    Apply multiple testing correction and obtain stats in a data frame.

    +
    # Apply multiple testing correction and obtain stats
    +stats_df <- limma::topTable(fit, number = ncol(module_eigengenes)) %>%
    +  tibble::rownames_to_column("module")
    +
    ## Removing intercept from test coefficients
    +

    Let’s take a look at the results. They are sorted with the most significant results at the top.

    +
    head(stats_df)
    +
    + +
    +

    Module 52 seems to be the most differentially expressed across refinebio_treatment groups. Now we can do some investigation into this module.

    +
    +
    +

    4.11 Let’s make plot of module 52

    +

    As a sanity check, let’s use ggplot to see what module 52’s eigengene looks like between treatment groups.

    +

    First we need to set up the module eigengene for this module with the sample metadata labels we need.

    +
    module_52_df <- module_eigengenes %>%
    +  tibble::rownames_to_column("accession_code") %>%
    +  # Here we are performing an inner join with a subset of metadata
    +  dplyr::inner_join(metadata %>%
    +    dplyr::select(refinebio_accession_code, refinebio_treatment),
    +  by = c("accession_code" = "refinebio_accession_code")
    +  )
    +

    Now we are ready for plotting.

    +
    ggplot(
    +  module_52_df,
    +  aes(
    +    x = refinebio_treatment,
    +    y = ME52,
    +    color = refinebio_treatment
    +  )
    +) +
    +  ggforce::geom_sina() +
    +  theme_classic()
    +

    +

    This makes sense! Looks like module 52 has elevated expression post treatment.

    +
    +
    +

    4.12 What genes are a part of module 52?

    +

    If you want to know which of your genes make up a modules, you can look at the $colors slot. This is a named list which associates the genes with the module they are a part of. We can turn this into a data frame for handy use.

    +
    gene_module_key <- tibble::enframe(bwnet$colors, name = "gene", value = "module") %>%
    +  # Let's add the `ME` part so its more clear what these numbers are and it matches elsewhere
    +  dplyr::mutate(module = paste0("ME", module))
    +

    Now we can find what genes are a part of module 52.

    +
    gene_module_key %>%
    +  dplyr::filter(module == "ME52")
    +
    + +
    +

    Let’s save this gene to module key to a TSV file for future use.

    +
    readr::write_tsv(gene_module_key,
    +  file = file.path("results", "SRP133573_wgcna_gene_to_module.tsv")
    +)
    +
    +
    +

    4.13 Make a custom heatmap function

    +

    We will make a heatmap that summarizes our differentially expressed module. Because we will make a couple of these, it makes sense to make a custom function for making this heatmap.

    +
    make_module_heatmap <- function(module_name,
    +                                expression_mat = normalized_counts,
    +                                metadata_df = metadata,
    +                                gene_module_key_df = gene_module_key,
    +                                module_eigengenes_df = module_eigengenes) {
    +  # Create a summary heatmap of a given module.
    +  #
    +  # Args:
    +  # module_name: a character indicating what module should be plotted, e.g. "ME52"
    +  # expression_mat: The full gene expression matrix. Default is `normalized_counts`.
    +  # metadata_df: a data frame with refinebio_accession_code and refinebio_treatment
    +  #              as columns. Default is `metadata`.
    +  # gene_module_key: a data.frame indicating what genes are a part of what modules. Default is `gene_module_key`.
    +  # module_eigengenes: a sample x eigengene data.frame with samples as rownames. Default is `module_eigengenes`.
    +  #
    +  # Returns:
    +  # A heatmap of expression matrix for a module's genes, with a barplot of the
    +  # eigengene expression for that module.
    +
    +  # Set up the module eigengene with its refinebio_accession_code
    +  module_eigengene <- module_eigengenes_df %>%
    +    dplyr::select(module_name) %>%
    +    tibble::rownames_to_column("refinebio_accession_code")
    +
    +  # Set up column annotation from metadata
    +  col_annot_df <- metadata_df %>%
    +    # Only select the treatment and sample ID columns
    +    dplyr::select(refinebio_accession_code, refinebio_treatment) %>%
    +    # Add on the eigengene expression by joining with sample IDs
    +    dplyr::inner_join(module_eigengene, by = "refinebio_accession_code") %>%
    +    # Arrange by treatment
    +    dplyr::arrange(refinebio_treatment, refinebio_accession_code) %>%
    +    # Store sample
    +    tibble::column_to_rownames("refinebio_accession_code")
    +
    +  # Create the ComplexHeatmap column annotation object
    +  col_annot <- ComplexHeatmap::HeatmapAnnotation(
    +    # Supply treatment labels
    +    refinebio_treatment = col_annot_df$refinebio_treatment,
    +    # Add annotation barplot
    +    module_eigengene = ComplexHeatmap::anno_barplot(dplyr::select(col_annot_df, module_name)),
    +    # Pick colors for each experimental group in refinebio_treatment
    +    col = list(refinebio_treatment = c("post-adt" = "#f1a340", "pre-adt" = "#998ec3"))
    +  )
    +
    +  # Get a vector of the Ensembl gene IDs that correspond to this module
    +  module_genes <- gene_module_key_df %>%
    +    dplyr::filter(module == module_name) %>%
    +    dplyr::pull(gene)
    +
    +  # Set up the gene expression data frame
    +  mod_mat <- expression_mat %>%
    +    t() %>%
    +    as.data.frame() %>%
    +    # Only keep genes from this module
    +    dplyr::filter(rownames(.) %in% module_genes) %>%
    +    # Order the samples to match col_annot_df
    +    dplyr::select(rownames(col_annot_df)) %>%
    +    # Data needs to be a matrix
    +    as.matrix()
    +
    +  # Normalize the gene expression values
    +  mod_mat <- mod_mat %>%
    +    # Scale can work on matrices, but it does it by column so we will need to
    +    # transpose first
    +    t() %>%
    +    scale() %>%
    +    # And now we need to transpose back
    +    t()
    +
    +  # Create a color function based on standardized scale
    +  color_func <- circlize::colorRamp2(
    +    c(-2, 0, 2),
    +    c("#67a9cf", "#f7f7f7", "#ef8a62")
    +  )
    +
    +  # Plot on a heatmap
    +  heatmap <- ComplexHeatmap::Heatmap(mod_mat,
    +    name = module_name,
    +    # Supply color function
    +    col = color_func,
    +    # Supply column annotation
    +    bottom_annotation = col_annot,
    +    # We don't want to cluster samples
    +    cluster_columns = FALSE,
    +    # We don't need to show sample or gene labels
    +    show_row_names = FALSE,
    +    show_column_names = FALSE
    +  )
    +
    +  # Return heatmap
    +  return(heatmap)
    +}
    +
    +
    +

    4.14 Make module heatmaps

    +

    Let’s try out the custom heatmap function with module 52 (our most differentially expressed module).

    +
    mod_52_heatmap <- make_module_heatmap(module_name = "ME52")
    +
    ## Note: Using an external vector in selections is ambiguous.
    +## ℹ Use `all_of(module_name)` instead of `module_name` to silence this message.
    +## ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
    +## This message is displayed once per session.
    +
    # Print out the plot
    +mod_52_heatmap
    +

    +

    From the barplot portion of our plot, we can see post-adt samples have higher values for this eigengene for module 52. In the heatmap portion, we can see how the individual genes that make up module 52 have more extreme values (very high or very low) in the post-adt samples.

    +

    We can save this plot to PDF.

    +
    pdf(file.path("results", "SRP133573_module_52_heatmap.pdf"))
    +mod_52_heatmap
    +dev.off()
    +
    ## png 
    +##   2
    +

    For comparison, let’s try out the custom heatmap function with a different, not differentially expressed module.

    +
    mod_10_heatmap <- make_module_heatmap(module_name = "ME10")
    +
    +# Print out the plot
    +mod_10_heatmap
    +

    +

    In this non-significant module’s heatmap, there’s not a particularly strong pattern between pre and post ADT samples. In general the expression of genes in module 10 does not vary much between groups, staying near the overall mean. There are a few samples and some genes that show higher expression, but it is not surprising this does not results in a significant overall difference between the groups.

    +

    Save this plot also.

    +
    pdf(file.path("results", "SRP133573_module_10_heatmap.pdf"))
    +mod_10_heatmap
    +dev.off()
    +
    ## png 
    +##   2
    @@ -4191,13 +4407,14 @@

    5 Resources for further learning<
  • WGCNA FAQ page (Langfelder and Horvath 2016).
  • WGCNA tutorial (Langfelder and Horvath 2016).
  • WGCNA paper (Langfelder and Horvath 2008).
  • +
  • ComplexHeatmap’s tutorial guide for more info on how to tweak the heatmaps (Gu 2020).
  • 6 Session info

    At the end of every analysis, before saving your notebook, we recommend printing out your session info. This helps make your code more reproducible by recording what versions of software and packages you used to run this.

    -
    # Print session info
    -sessionInfo()
    +
    # Print session info
    +sessionInfo()
    ## R version 4.0.2 (2020-06-22)
     ## Platform: x86_64-pc-linux-gnu (64-bit)
     ## Running under: Ubuntu 20.04 LTS
    @@ -4228,43 +4445,51 @@ 

    6 Session info

    ## [15] BiocGenerics_0.36.0 optparse_1.6.6 ## ## loaded via a namespace (and not attached): -## [1] colorspace_1.4-1 ellipsis_0.3.1 htmlTable_2.1.0 -## [4] XVector_0.30.0 base64enc_0.1-3 rstudioapi_0.11 -## [7] farver_2.0.3 getopt_1.20.3 bit64_4.0.5 -## [10] AnnotationDbi_1.52.0 fansi_0.4.1 codetools_0.2-16 -## [13] splines_4.0.2 R.methodsS3_1.8.1 doParallel_1.0.15 -## [16] impute_1.64.0 geneplotter_1.68.0 knitr_1.30 -## [19] Formula_1.2-3 annotate_1.68.0 cluster_2.1.0 -## [22] GO.db_3.12.1 png_0.1-7 R.oo_1.24.0 -## [25] readr_1.4.0 compiler_4.0.2 httr_1.4.2 -## [28] backports_1.1.10 assertthat_0.2.1 Matrix_1.2-18 -## [31] cli_2.1.0 htmltools_0.5.0 tools_4.0.2 -## [34] gtable_0.3.0 glue_1.4.2 GenomeInfoDbData_1.2.4 -## [37] dplyr_1.0.2 Rcpp_1.0.5 styler_1.3.2 -## [40] vctrs_0.3.4 preprocessCore_1.52.0 iterators_1.0.12 -## [43] xfun_0.18 stringr_1.4.0 ps_1.4.0 -## [46] lifecycle_0.2.0 XML_3.99-0.5 zlibbioc_1.36.0 -## [49] scales_1.1.1 hms_0.5.3 rematch2_2.1.2 -## [52] RColorBrewer_1.1-2 yaml_2.2.1 memoise_1.1.0 -## [55] gridExtra_2.3 rpart_4.1-15 latticeExtra_0.6-29 -## [58] stringi_1.5.3 RSQLite_2.2.1 genefilter_1.72.0 -## [61] foreach_1.5.0 checkmate_2.0.0 BiocParallel_1.24.1 -## [64] rlang_0.4.8 pkgconfig_2.0.3 bitops_1.0-6 -## [67] evaluate_0.14 lattice_0.20-41 purrr_0.3.4 -## [70] htmlwidgets_1.5.2 labeling_0.3 bit_4.0.4 -## [73] tidyselect_1.1.0 R6_2.4.1 generics_0.0.2 -## [76] Hmisc_4.4-1 DelayedArray_0.16.0 DBI_1.1.0 -## [79] pillar_1.4.6 foreign_0.8-80 withr_2.3.0 -## [82] survival_3.1-12 RCurl_1.98-1.2 nnet_7.3-14 -## [85] tibble_3.0.4 crayon_1.3.4 rmarkdown_2.4 -## [88] jpeg_0.1-8.1 locfit_1.5-9.4 grid_4.0.2 -## [91] data.table_1.13.0 blob_1.2.1 digest_0.6.25 -## [94] xtable_1.8-4 R.cache_0.14.0 R.utils_2.10.1 -## [97] munsell_0.5.0
    +## [1] colorspace_1.4-1 rjson_0.2.20 ellipsis_0.3.1 +## [4] circlize_0.4.10 htmlTable_2.1.0 XVector_0.30.0 +## [7] GlobalOptions_0.1.2 base64enc_0.1-3 clue_0.3-57 +## [10] rstudioapi_0.11 farver_2.0.3 getopt_1.20.3 +## [13] bit64_4.0.5 AnnotationDbi_1.52.0 fansi_0.4.1 +## [16] codetools_0.2-16 splines_4.0.2 R.methodsS3_1.8.1 +## [19] doParallel_1.0.15 impute_1.64.0 geneplotter_1.68.0 +## [22] knitr_1.30 polyclip_1.10-0 jsonlite_1.7.1 +## [25] Formula_1.2-3 Cairo_1.5-12.2 annotate_1.68.0 +## [28] cluster_2.1.0 GO.db_3.12.1 png_0.1-7 +## [31] R.oo_1.24.0 ggforce_0.3.2 readr_1.4.0 +## [34] compiler_4.0.2 httr_1.4.2 backports_1.1.10 +## [37] assertthat_0.2.1 Matrix_1.2-18 limma_3.46.0 +## [40] cli_2.1.0 tweenr_1.0.1 htmltools_0.5.0 +## [43] tools_4.0.2 gtable_0.3.0 glue_1.4.2 +## [46] GenomeInfoDbData_1.2.4 dplyr_1.0.2 Rcpp_1.0.5 +## [49] styler_1.3.2 vctrs_0.3.4 preprocessCore_1.52.0 +## [52] iterators_1.0.12 xfun_0.18 stringr_1.4.0 +## [55] ps_1.4.0 lifecycle_0.2.0 XML_3.99-0.5 +## [58] MASS_7.3-51.6 zlibbioc_1.36.0 scales_1.1.1 +## [61] hms_0.5.3 rematch2_2.1.2 RColorBrewer_1.1-2 +## [64] ComplexHeatmap_2.6.0 yaml_2.2.1 memoise_1.1.0 +## [67] gridExtra_2.3 rpart_4.1-15 latticeExtra_0.6-29 +## [70] stringi_1.5.3 RSQLite_2.2.1 genefilter_1.72.0 +## [73] foreach_1.5.0 checkmate_2.0.0 BiocParallel_1.24.1 +## [76] shape_1.4.5 rlang_0.4.8 pkgconfig_2.0.3 +## [79] bitops_1.0-6 evaluate_0.14 lattice_0.20-41 +## [82] purrr_0.3.4 htmlwidgets_1.5.2 labeling_0.3 +## [85] bit_4.0.4 tidyselect_1.1.0 R6_2.4.1 +## [88] magick_2.4.0 generics_0.0.2 Hmisc_4.4-1 +## [91] DelayedArray_0.16.0 DBI_1.1.0 pillar_1.4.6 +## [94] foreign_0.8-80 withr_2.3.0 survival_3.1-12 +## [97] RCurl_1.98-1.2 nnet_7.3-14 tibble_3.0.4 +## [100] crayon_1.3.4 rmarkdown_2.4 GetoptLong_1.0.3 +## [103] jpeg_0.1-8.1 locfit_1.5-9.4 grid_4.0.2 +## [106] data.table_1.13.0 blob_1.2.1 digest_0.6.25 +## [109] xtable_1.8-4 R.cache_0.14.0 R.utils_2.10.1 +## [112] munsell_0.5.0

    References

    +
    +

    Gu Z., 2020 ComplexHeatmap complete reference. https://jokergoo.github.io/ComplexHeatmap-reference/book/

    +

    Hastie T., R. Tibshirani, B. Narasimhan, and G. Chu, 2020 Impute: Imputation for microarray data. https://www.bioconductor.org/packages/devel/bioc/manuals/impute/man/impute.pdf

    From 26585088fbd22647c2884a9b8d726c05ef2f3c61 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Tue, 24 Nov 2020 09:48:20 -0500 Subject: [PATCH 45/50] WGCNA Part 4: Warn about Outliers (#364) * Put in basic changes: navbar, dict, snakefile, Rmd * More polishing and info and refs * Update file paths * Bring back docker changes * Add to dictionary * Add a couple refs * Add next steps * Add some polishing and refs * Address the straightforward items from cbethell 's review * Incorporate jashapiro review from #358 * Style Rmds * Bring over part1 changes and re-render * Add last set of steps * Push this partcular plot version in case we wanna come back to it * Commit this multiple module pheatmap in case I want to return to it * ComplexHeatmap is mostly wrangled * It's working! * Save to PDFs * Fix color function and re-render * Add outlier thing * Style Rmds * Re-rendered html * switch the whole outlier thing to just a comment * re-render after staging merge Co-authored-by: GitHub Actions --- 04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd | 6 ++++++ 04-advanced-topics/network-analysis_rnaseq_01_wgcna.html | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd index 6553f6e2..bee42c53 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd @@ -335,6 +335,12 @@ For more information about these transformation methods, [see here](https://alex dds_norm <- vst(dds) ``` +At this point, if your data set has any outlier samples, you should look into removing them as they can affect your WGCNA results. + +WGCNA's tutorial has [an example of exploring your data for outliers you can reference](https://horvath.genetics.ucla.edu/html/CoexpressionNetwork/Rpackages/WGCNA/Tutorials/FemaleLiver-01-dataInput.pdf). + +For this example data set, we will skip this step (there are no obvious outliers) and proceed. + ## Format normalized data for WGCNA Extract the normalized counts to a matrix and transpose it so we can pass it to WGCNA. diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html index b81a41c6..b294fb8d 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html @@ -3713,6 +3713,7 @@
  • Dimension Reduction - UMAP
  • Pathway Analysis - ORA
  • Pathway Analysis - GSEA
  • +
  • Pathway Analysis - GSVA
  • Ensembl Gene ID Annotation
  • Ortholog Mapping
  • @@ -4028,7 +4029,7 @@

    4.2 Import and set up data

    # Read in metadata TSV file
     metadata <- readr::read_tsv(metadata_file)
    ## 
    -## ── Column specification ──────────────────────────────────────────────────────────────────
    +## ── Column specification ───────────────────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_character(),
     ##   refinebio_age = col_logical(),
    @@ -4048,7 +4049,7 @@ 

    4.2 Import and set up data

    # Here we are going to store the gene IDs as rownames so that we can have a numeric matrix to perform calculations on later tibble::column_to_rownames("Gene")
    ## 
    -## ── Column specification ──────────────────────────────────────────────────────────────────
    +## ── Column specification ───────────────────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_double(),
     ##   Gene = col_character()
    @@ -4101,6 +4102,7 @@ 

    4.4 Perform DESeq2 normalization
    # Normalize and transform the data in the `DESeqDataSet` object using the `vst()`
     # function from the `DESEq2` R package
     dds_norm <- vst(dds)
    +

    At this point, if your data has any outliers, you should look into removing them as they can affect your WGCNA results. WGCNA’s tutorial has an example of exploring your data for outliers you can reference.

    4.5 Format normalized data for WGCNA

    @@ -4249,7 +4251,7 @@

    4.11 Let’s make plot of module ) + ggforce::geom_sina() + theme_classic()

    -

    +

    This makes sense! Looks like module 52 has elevated expression post treatment.

    From ae9aea8d93e92b4caa742a901e81d366b814062e Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 25 Nov 2020 09:07:07 -0500 Subject: [PATCH 46/50] Microarray ORA Restructure Instruction (#377) * Some edits and adding other tutorials * Add more guidance about why pick ORA * A bit more word changing * A few more wording edits * Incorporating jashapiro review * Get rid of other GSEA mention * sessioninfo::session_info() * Put those two wording things in jashapiro mentioned --- .../pathway-analysis_microarray_01_ora.Rmd | 42 +++++++++++-------- .../pathway-analysis_microarray_01_ora.html | 36 +++++++++------- components/references.bib | 8 ++++ 3 files changed, 54 insertions(+), 32 deletions(-) diff --git a/02-microarray/pathway-analysis_microarray_01_ora.Rmd b/02-microarray/pathway-analysis_microarray_01_ora.Rmd index 92e13652..7c071bd1 100644 --- a/02-microarray/pathway-analysis_microarray_01_ora.Rmd +++ b/02-microarray/pathway-analysis_microarray_01_ora.Rmd @@ -13,8 +13,12 @@ output: This example is one of pathway analysis module set, we recommend looking at the [pathway analysis table below](#how-to-choose-a-pathway-analysis) to help you determine which pathway analysis method is best suited for your purposes. -This particular example analysis shows how you can use over-representation analysis (ORA) to determine if a set of genes (e.g., those differentially expressed using some cutoff) shares more or fewer genes with gene sets/pathways than we would expect at random. -This pathway analysis method does not require any particular sample size, since the only input from your dataset is a set of genes of interest [@Yaari2013]. +This particular example analysis shows how you can use over-representation analysis (ORA) to determine if a set of genes (e.g., those differentially expressed using some cutoff) shares more or fewer genes with gene sets/pathways than we would expect by chance. + +ORA is a broadly applicable technique that may be good in scenarios where your dataset or scientific questions don't fit the requirements of other pathway analyses methods. +It also does not require any particular sample size, since the only input from your dataset is a set of genes of interest [@Yaari2013]. + +If you have differential expression results or something with a gene-level ranking and a two-group comparison, we recommend considering [GSEA](https://alexslemonade.github.io/refinebio-examples/02-microarray/pathway-analysis_microarray_02_gsea.html) for your pathway analysis questions. ⬇️ [**Jump to the analysis code**](#analysis) ⬇️ @@ -111,7 +115,9 @@ If the concept of a "file path" is unfamiliar to you; we recommend taking a look # Using a different refine.bio dataset with this analysis? -If you'd like to adapt an example analysis to use a different dataset from [refine.bio](https://www.refine.bio/), we recommend placing the files in the `data/` directory you created and changing the filenames and paths in the notebook to match these files (we've put comments to signify where you would need to change the code). +If you'd like to adapt an example analysis to use a different dataset from [refine.bio](https://www.refine.bio/), we recommend replacing the `dge_url` with a different file path to a gene list that you are interested in. +The file we use here has several columns of differential expression summary statistics, so if your gene list does not have the exact same information, many steps will need to be changed or deleted entirely depending on what your gene list file looks like (particularly in the [`Determine our genes of interest list` section](#determined-our-genes-of-interest-list)). + We suggest saving plots and results to `plots/` and `results/` directories, respectively, as these are automatically created by the notebook. From here you can customize this analysis example to fit your own scientific questions and preferences. @@ -170,7 +176,10 @@ library(magrittr) ## Import data -We will read in the differential expression results we will download from online. +For ORA, we only need a list of gene IDs as our input, so this example can work for any situations where you have gene list and want to know more about what biological pathways it shares genes with. + +For this example, we will read in results from a differential expression analysis that we have already performed. +Rather than reading from a local file, we will download the results table directly from a URL. These results are from a zebrafish microarray experiment we used for [differential expression analysis for two groups](https://alexslemonade.github.io/refinebio-examples/02-microarray/differential-expression_microarray_02_2-groups.html) using [`limma`](https://bioconductor.org/packages/release/bioc/html/limma.html) [@Ritchie2015]. The table contains Ensembl gene IDs, log fold-changes for each group, and adjusted p-values (FDR in this case). We can identify differentially regulated genes by filtering these results and use this list as input to ORA. @@ -247,8 +256,6 @@ dr_kegg_df <- dr_msigdb_df %>% ) ``` -Note: We could have specified that we wanted the KEGG gene sets using the `category` and `subcategory` arguments of `msigdbr()`, but we're going for general steps! -- use `?msigdbr` to see more information. - The `clusterProfiler()` function we will use requires a data frame with two columns, where one column contains the term identifier or name and one column contains gene identifiers that match our gene lists we want to check for enrichment. Our data frame with KEGG terms contains Entrez IDs and gene symbols. @@ -339,22 +346,22 @@ head(dge_annot_df) ## Over-representation Analysis (ORA) -Over-representation testing using `clusterProfiler` is based on a hypergeometric test [@clusterProfiler-book]. +Over-representation testing using `clusterProfiler` is based on a hypergeometric test (often referred to as Fisher's exact test) [@clusterProfiler-book]. +For more background on hypergeometric tests, this [handy tutorial](https://dputhier.github.io/ASG/practicals/go_statistics_td/go_statistics_td_2015.html) explains more about how hypergeometric tests work [@Puthier2015]. -\(p = 1 - \displaystyle\sum_{i = 0}^{k-1}\frac{ {M \choose i}{ {N-M} \choose {n-i} } } { {N \choose n} }\) +We will need to provide to `clusterProfiler` two genes lists: -Where `N` is the number of genes in the background distribution, `M` is the number of genes in a pathway, `n` is the number of genes we are interested in (our differentially expressed genes), and `k` is the number of genes that overlap between the pathway and our genes of interest. - -So, we will need to provide to `clusterProfiler` two genes lists: - -1) Our genes of interest (`n`) -2) What genes were in our total background set (`N`). (All genes that originally had an opportunity to be measured). +1) Our genes of interest +2) What genes were in our total background set. (All genes that originally had an opportunity to be measured). ## Determine our genes of interest list We will use our differential expression results to get a genes of interest list. Let's use our adjusted p values as a cutoff. +This step is highly variable depending on what your gene list is, what information it contains and what your goals are. +You may want to delete this next chunk entirely if you supply an already determined list of genes OR you may need to adjust the cutoffs and column names. + ```{r} # Select genes that are below a cutoff genes_of_interest <- dge_annot_df %>% @@ -411,9 +418,6 @@ kegg_ora_results <- enricher( *Note: using `enrichKEGG()` is a shortcut for doing ORA using KEGG, but the approach we covered here can be used with any gene sets you'd like!* -What is returned by `enricher()`? -You can run `View(kegg_ora_results)` or click on the object in your Environment panel. - The information we're most likely interested in is in the `results` slot. Let's convert this into a data frame that we can write to file. @@ -485,6 +489,8 @@ readr::write_tsv( # Resources for further learning +- [Hypergeometric test exercises](https://dputhier.github.io/ASG/practicals/go_statistics_td/go_statistics_td_2015.html)[@Puthier2015]. +- [clusterProfiler ORA tutorial](https://learn.gencore.bio.nyu.edu/rna-seq-analysis/over-representation-analysis/#:~:text=Over%2Drepresentation%20(or%20enrichment),a%20subset%20of%20your%20data.) - [clusterProfiler paper](https://doi.org/10.1089/omi.2011.0118) [@Yu2012]. - [clusterProfiler book](https://yulab-smu.github.io/clusterProfiler-book/index.html) [@clusterProfiler-book]. - [This handy review](https://doi.org/10.1371/journal.pcbi.1002375) which summarizes the different types of pathway analysis and their limitations [@Khatri2012]. @@ -496,7 +502,7 @@ This helps make your code more reproducible by recording what versions of softwa ```{r} # Print session info -sessionInfo() +sessioninfo::session_info() ``` # References diff --git a/02-microarray/pathway-analysis_microarray_01_ora.html b/02-microarray/pathway-analysis_microarray_01_ora.html index 5306c515..cd2753ef 100644 --- a/02-microarray/pathway-analysis_microarray_01_ora.html +++ b/02-microarray/pathway-analysis_microarray_01_ora.html @@ -3713,6 +3713,7 @@
  • Dimension Reduction - UMAP
  • Pathway Analysis - ORA
  • Pathway Analysis - GSEA
  • +
  • Pathway Analysis - GSVA
  • Ensembl Gene ID Annotation
  • Ortholog Mapping
  • @@ -3741,7 +3742,7 @@ @@ -3772,11 +3773,13 @@

    November 2020

    1 Purpose of this analysis

    This example is one of pathway analysis module set, we recommend looking at the pathway analysis table below to help you determine which pathway analysis method is best suited for your purposes.

    -

    This particular example analysis shows how you can use over-representation analysis (ORA) to determine if a set of genes (e.g., those differentially expressed using some cutoff) shares more or fewer genes with gene sets/pathways than we would expect at random. This pathway analysis method does not require any particular sample size, since the only input from your dataset is a set of genes of interest (Yaari et al. 2013).

    +

    This particular example analysis shows how you can use over-representation analysis (ORA) to determine if a set of genes (e.g., those differentially expressed using some cutoff) shares more or fewer genes with gene sets/pathways than we would expect at random.

    +

    ORA is a broadly applicable technique that may be good in scenarios where your dataset or scientific questions don’t fit the requirements of other pathway analyses methods. It also does not require any particular sample size, since the only input from your dataset is a set of genes of interest (Yaari et al. 2013).

    +

    If you have differential expression results or something with a gene-level ranking and a two-group comparison, we recommend considering GSEA for your pathway analysis questions.

    ⬇️ Jump to the analysis code ⬇️

    1.0.1 What is pathway analysis?

    -

    We refer to any technique that uses predetermined sets of genes that are related or coordinated in their expression in some way (e.g., participate in the same molecular process, are regulated by the same transcription factor) to interpret a high-throughput experiment as pathway analysis. In the context of refine.bio, we use these techniques to analyze and interpret genome-wide gene expression experiments. The rationale for performing pathway analysis is that looking at the pathway-level may be more biologically meaningful than considering individual genes, especially if a large number of genes are differentially expressed between conditions of interest. In addition, many relatively small changes in the expression values of genes in the same pathway could lead to a phenotypic outcome and these small changes may go undetected in differential gene expression analysis.

    +

    Pathway analysis refers to any one of many techniques that uses predetermined sets of genes that are related or coordinated in their expression in some way (e.g., participate in the same molecular process, are regulated by the same transcription factor) to interpret a high-throughput experiment. In the context of refine.bio, we use these techniques to analyze and interpret genome-wide gene expression experiments. The rationale for performing pathway analysis is that looking at the pathway-level may be more biologically meaningful than considering individual genes, especially if a large number of genes are differentially expressed between conditions of interest. In addition, many relatively small changes in the expression values of genes in the same pathway could lead to a phenotypic outcome and these small changes may go undetected in differential gene expression analysis.

    We highly recommend taking a look at Ten Years of Pathway Analysis: Current Approaches and Outstanding Challenges from Khatri et al. (2012) for a more comprehensive overview. We have provided primary publications and documentation of the methods we will introduce below as well as some recommended reading in the Resources for further learning section.

    @@ -3886,7 +3889,9 @@

    2.5 Check out our file structure!

    3 Using a different refine.bio dataset with this analysis?

    -

    If you’d like to adapt an example analysis to use a different dataset from refine.bio, we recommend placing the files in the data/ directory you created and changing the filenames and paths in the notebook to match these files (we’ve put comments to signify where you would need to change the code). We suggest saving plots and results to plots/ and results/ directories, respectively, as these are automatically created by the notebook. From here you can customize this analysis example to fit your own scientific questions and preferences.

    +

    If you’d like to adapt an example analysis to use a different dataset from refine.bio, we recommend replacing the dge_url with a different file path to a gene list that you are interested in. The file we use here has several columns of differential expression summary statistics, so if your gene list does not have the exact same information, many steps will need to be changed or deleted entirely depending on what your gene list file looks like (particularly in the Determine our genes of interest list section).

    +

    If you have differential expression results or something with a gene-level ranking and a two-group comparison, we recommend considering GSEA for your pathway analysis questions.

    +

    We suggest saving plots and results to plots/ and results/ directories, respectively, as these are automatically created by the notebook. From here you can customize this analysis example to fit your own scientific questions and preferences.


     

    @@ -3990,7 +3995,8 @@

    4.1 Install libraries

    4.2 Import data

    -

    We will read in the differential expression results we will download from online. These results are from a zebrafish microarray experiment we used for differential expression analysis for two groups using limma (Ritchie et al. 2015). The table contains Ensembl gene IDs, log fold-changes for each group, and adjusted p-values (FDR in this case). We can identify differentially regulated genes by filtering these results and use this list as input to ORA.

    +

    For ORA, we only need a list of gene IDs as our input, so this example can work for any situations where you have gene list and want to know more about what biological pathways it shares genes with.

    +

    For this example, we will read in results from a differential expression analysis that we have already performed. Rather than reading from a local file, we will download the results table directly from a URL. These results are from a zebrafish microarray experiment we used for differential expression analysis for two groups using limma (Ritchie et al. 2015). The table contains Ensembl gene IDs, log fold-changes for each group, and adjusted p-values (FDR in this case). We can identify differentially regulated genes by filtering these results and use this list as input to ORA.

    Instead of using the URL below, you can use a file path to a TSV file with your desired gene list results. First we will assign the URL to its own variable called, dge_url.

    # Define the url to your differential expression results file
     dge_url <- "https://refinebio-examples.s3.us-east-2.amazonaws.com/02-microarray/results/GSE71270/GSE71270_limma_results.tsv"
    @@ -4000,7 +4006,7 @@

    4.2 Import data

    # desired gene list results dge_df <- readr::read_tsv(dge_url)
    ## 
    -## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────────────────────────
    +## ── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────────────
     ## cols(
     ##   Gene = col_character(),
     ##   logFC = col_double(),
    @@ -4055,7 +4061,6 @@ 

    4.3 Getting familiar with c gs_cat == "C2", # This is to filter only to the C2 curated gene sets gs_subcat == "CP:KEGG" # This is because we only want KEGG pathways )

    -

    Note: We could have specified that we wanted the KEGG gene sets using the category and subcategory arguments of msigdbr(), but we’re going for general steps! – use ?msigdbr to see more information.

    The clusterProfiler() function we will use requires a data frame with two columns, where one column contains the term identifier or name and one column contains gene identifiers that match our gene lists we want to check for enrichment.

    Our data frame with KEGG terms contains Entrez IDs and gene symbols.

    In our differential expression results data frame, dge_df we have Ensembl gene identifiers. So we will need to convert our Ensembl IDs into either gene symbols or Entrez IDs.

    @@ -4126,18 +4131,17 @@

    4.4 Gene identifier conversion

    4.5 Over-representation Analysis (ORA)

    -

    Over-representation testing using clusterProfiler is based on a hypergeometric test (Yu).

    -

    \(p = 1 - \displaystyle\sum_{i = 0}^{k-1}\frac{ {M \choose i}{ {N-M} \choose {n-i} } } { {N \choose n} }\)

    -

    Where N is the number of genes in the background distribution, M is the number of genes in a pathway, n is the number of genes we are interested in (our differentially expressed genes), and k is the number of genes that overlap between the pathway and our genes of interest.

    -

    So, we will need to provide to clusterProfiler two genes lists:

    +

    Over-representation testing using clusterProfiler is based on a hypergeometric test (Yu). For more background on hypergeometric tests, this handy tutorial explains more about how hypergeometric tests work (Puthier and van Helden 2015).

    +

    We will need to provide to clusterProfiler two genes lists:

      -
    1. Our genes of interest (n)
    2. -
    3. What genes were in our total background set (N). (All genes that originally had an opportunity to be measured).
    4. +
    5. Our genes of interest
    6. +
    7. What genes were in our total background set. (All genes that originally had an opportunity to be measured).

    4.6 Determine our genes of interest list

    We will use our differential expression results to get a genes of interest list. Let’s use our adjusted p values as a cutoff.

    +

    This step is highly variable depending on what your gene list is, what information it contains and what your goals are. You may want to delete this next chunk entirely if you supply an already determined list of genes OR you may need to adjust the cutoffs and column names.

    # Select genes that are below a cutoff
     genes_of_interest <- dge_annot_df %>%
       # Here we want the top differentially expressed genes and we will use downregulated genes
    @@ -4178,7 +4182,6 @@ 

    4.8 Run ORA using the enric ) )

    Note: using enrichKEGG() is a shortcut for doing ORA using KEGG, but the approach we covered here can be used with any gene sets you’d like!

    -

    What is returned by enricher()? You can run View(kegg_ora_results) or click on the object in your Environment panel.

    The information we’re most likely interested in is in the results slot. Let’s convert this into a data frame that we can write to file.

    kegg_result_df <- data.frame(kegg_ora_results@result)

    Let’s print out a sneak peek of it here and take a look at how many sets do we have that fit our cutoff of 0.1 FDR?

    @@ -4230,6 +4233,8 @@

    4.10 Write results to file

    5 Resources for further learning

      +
    • Hypergeometric test exercises(Puthier and van Helden 2015).
    • +
    • clusterProfiler ORA tutorial
    • clusterProfiler paper (Yu et al. 2012).
    • clusterProfiler book (Yu).
    • This handy review which summarizes the different types of pathway analysis and their limitations (Khatri et al. 2012).
    • @@ -4316,6 +4321,9 @@

      References

      Khatri P., M. Sirota, and A. J. Butte, 2012 Ten years of pathway analysis: Current approaches and outstanding challenges. PLOS Computational Biology 8: e1002375. https://doi.org/10.1371/journal.pcbi.1002375

      +
      +

      Puthier D., and J. van Helden, 2015 Statistics for Bioinformatics - Practicals - Gene enrichment statistics. https://dputhier.github.io/ASG/practicals/go_statistics_td/go_statistics_td_2015.html

      +

      Ritchie M. E., B. Phipson, D. Wu, Y. Hu, and C. W. Law et al., 2015 limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Research 43: e47. https://doi.org/10.1093/nar/gkv007

      diff --git a/components/references.bib b/components/references.bib index 218b44c9..ddede529 100644 --- a/components/references.bib +++ b/components/references.bib @@ -639,6 +639,14 @@ @manual{Prabhakaran2016 url = {http://r-statistics.co/Complete-Ggplot2-Tutorial-Part1-With-R-Code.html} } +@manual{Puthier2015, + title = {Statistics for {B}ioinformatics - {P}racticals - {G}ene enrichment statistics}, + author = {Denis Puthier and Jacques {van Helden}}, + year = {2015}, + month = {Nov}, + url = {https://dputhier.github.io/ASG/practicals/go_statistics_td/go_statistics_td_2015.html}, + } + @manual{R-base, title = {{R}: A Language and Environment for Statistical Computing}, author = {{R Core Team}}, From 3a2f92eaceeab58ea2df03c0e106cba0699f1d39 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Wed, 25 Nov 2020 12:21:30 -0500 Subject: [PATCH 47/50] WGCNA Part 5: switch dataset (#379) * switch wording and dataset in general * Few more wording edits * Update dictionary; fix spelling errors * Re-render! * Change to 7 and incorporate jashapiro review * Also switch the most sig module! * Two comments from jashapiro review * Put the comments too * Style Rmds * Use all_of() to get rid warning * Style Rmds * Re-render Co-authored-by: GitHub Actions --- .../network-analysis_rnaseq_01_wgcna.Rmd | 143 +++--- .../network-analysis_rnaseq_01_wgcna.html | 413 +++++++++++------- components/dictionary.txt | 4 + 3 files changed, 332 insertions(+), 228 deletions(-) diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd index bee42c53..fda3c87f 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd @@ -13,7 +13,7 @@ output: In this example, we use weighted gene co-expression network analysis (WGCNA) to identify co-expressed gene modules [@Langfelder2008]. WGCNA uses a series of correlations to identify sets of genes that are expressed together in your data set. -This is a fairly intuitive approach to gene network analysis which can aid in interpretation of microarray & RNAseq data. +This is a fairly intuitive approach to gene network analysis which can aid in interpretation of microarray & RNA-seq data. As output, WGCNA gives groups of co-expressed genes as well as an eigengene x sample matrix (where the values for each eigengene represent the summarized expression for a group of co-expressed genes) [@Langfelder2007]. This eigengene x sample data can, in many instances, be used as you would the original gene expression values. @@ -75,7 +75,7 @@ In the same place you put this `.Rmd` file, you should now have three new empty For general information about downloading data for these examples, see our ['Getting Started' section](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-the-data). -Go to this [dataset's page on refine.bio](https://www.refine.bio/experiments/SRP133573/identification-of-transcription-factor-relationships-associated-with-androgen-deprivation-therapy-response-and-metastatic-progression-in-prostate-cancer). +Go to this [dataset's page on refine.bio](https://www.refine.bio/experiments/SRP140558). Click the "Download Now" button on the right side of this screen. @@ -96,9 +96,9 @@ You will get an email when it is ready. ## About the dataset we are using for this example -For this example analysis, we will use this [prostate cancer dataset](https://www.refine.bio/experiments/SRP133573). -The data that we downloaded from refine.bio for this analysis has 175 RNA-seq samples obtained from 20 patients with prostate cancer. -Patients underwent androgen deprivation therapy (ADT) and RNA-seq samples include pre-ADT biopsies and post-ADT prostatectomy specimens. +For this example analysis, we will use this [acute viral bronchiolitis dataset](https://www.refine.bio/experiments/SRP140558). +The data that we downloaded from refine.bio for this analysis has 62 paired peripheral blood mononuclear cell RNA-seq samples obtained from 31 patients. +Samples were collected at two time points: during their first, acute bronchiolitis visit (abbreviated "AV") and their recovery, their post-convalescence visit (abbreviated "CV"). ## Place the dataset in your new `data/` folder @@ -113,7 +113,7 @@ For more details on the contents of this folder see [these docs on refine.bio](h The `` folder has the data and metadata TSV files you will need for this example analysis. Experiment accession ids usually look something like `GSE1235` or `SRP12345`. -Copy and paste the `SRP133573` folder into your newly created `data/` folder. +Copy and paste the `SRP140558` folder into your newly created `data/` folder. ## Check out our file structure! @@ -121,7 +121,7 @@ Your new analysis folder should contain: - The example analysis `.Rmd` you downloaded - A folder called "data" which contains: - - The `SRP133573` folder which contains: + - The `SRP140558` folder which contains: - The gene expression - The metadata TSV - A folder for `plots` (currently empty) @@ -139,13 +139,13 @@ This is handy to do because if we want to switch the dataset (see next section f ```{r} # Define the file path to the data directory -data_dir <- file.path("data", "SRP133573") # Replace with accession number which will be the name of the folder the files will be in +data_dir <- file.path("data", "SRP140558") # Replace with accession number which will be the name of the folder the files will be in # Declare the file path to the gene expression matrix file using the data directory saved as `data_dir` -data_file <- file.path(data_dir, "SRP133573.tsv") # Replace with file path to your dataset +data_file <- file.path(data_dir, "SRP140558.tsv") # Replace with file path to your dataset # Declare the file path to the metadata file using the data directory saved as `data_dir` -metadata_file <- file.path(data_dir, "metadata_SRP133573.tsv") # Replace with file path to your metadata +metadata_file <- file.path(data_dir, "metadata_SRP140558.tsv") # Replace with file path to your metadata ``` Now that our file paths are declared, we can use the `file.exists()` function to check that the files are where we specified above. @@ -273,7 +273,7 @@ all.equal(colnames(df), metadata$refinebio_accession_code) ### Prepare data for `DESeq2` -There are two things we neeed to do to prep our expression data for DESeq2. +There are two things we need to do to prep our expression data for DESeq2. First, we need to make sure all of the values in our data are converted to integers as required by a `DESeq2` function we will use later. @@ -291,23 +291,36 @@ df <- round(df) %>% dplyr::filter(rowSums(.) >= 50) ``` -Another thing we need to do is make sure our main experimental group label is set up. -In this case `refinebio_treatment` has two groups: `pre-adt` and `post-adt`. -To keep these two treatments in logical (rather than alphabetical) order, we will convert this to a factor with `pre-adt` as the first level. +Another thing we need to do is set up our main experimental group variable. +Unfortunately the metadata for this dataset are not set up into separate, neat columns, but we can accomplish that ourselves. + +For this study, PBMCs were collected at two time points: during the patients' first, acute bronchiolitis visit (abbreviated "AV") and their recovery visit, (called post-convalescence and abbreviated "CV"). + +For handier use of this information, we can create a new variable, `time_point`, that states this info more clearly. +This new `time_point` variable will have two labels: `acute illness` and `recovering` based on the `AV` or `CV` coding located in the `refinebio_title` string variable. ```{r} metadata <- metadata %>% - dplyr::mutate(refinebio_treatment = factor(refinebio_treatment, - levels = c("pre-adt", "post-adt") - )) + dplyr::mutate( + time_point = dplyr::case_when( + # Create our new variable based on refinebio_title containing AV/CV + stringr::str_detect(refinebio_title, "_AV_") ~ "acute illness", + stringr::str_detect(refinebio_title, "_CV_") ~ "recovering" + ), + # It's easier for future items if this is already set up as a factor + time_point = as.factor(time_point) + ) ``` Let's double check that our factor set up is right. +We want `acute illness` to be the first level since it was the first time point collected. ```{r} -levels(metadata$refinebio_treatment) +levels(metadata$time_point) ``` +Great! We're all set. + ## Create a DESeqDataset We will be using the `DESeq2` package for [normalizing and transforming our data](https://alexslemonade.github.io/refinebio-examples/03-rnaseq/00-intro-to-rnaseq.html#deseq2-transformation-methods), which requires us to format our data into a `DESeqDataSet` object. @@ -384,7 +397,7 @@ ggplot(sft_df, aes(x = Power, y = model_fit, label = Power)) + # We will plot what WGCNA recommends as an R^2 cutoff geom_hline(yintercept = 0.80, col = "red") + # Just in case our values are low, we want to make sure we can still see the 0.80 level - ylim(c(min(sft_df$model_fit), 1)) + + ylim(c(min(sft_df$model_fit), 1.05)) + # We can add more sensible labels for our axis xlab("Soft Threshold (power)") + ylab("Scale Free Topology Model Fit, signed R^2") + @@ -399,14 +412,14 @@ WGCNA's authors recommend using a `power` that has an signed $R^2$ above `0.80`, If you have multiple power values with signed $R^2$ above `0.80`, then picking the one at an inflection point, in other words where the $R^2$ values seem to have reached their saturation [@Zhang2005]. You want to a `power` that gives you a big enough $R^2$ but is not excessively large. -So using the plot above, going with a power soft-threshold of `16`! +So using the plot above, going with a power soft-threshold of `7`! If you find you have all very low $R^2$ values this may be because there are too many genes with low expression values that are cluttering up the calculations. You can try returning to [gene filtering step](#define-a-minimum-counts-cutoff) and choosing a more stringent cutoff (you'll then need to re-run the transformation and subsequent steps to remake this plot to see if that helped). ## Run WGCNA! -We will use the `blockwiseModules()` function to find gene co-expression modules in WGCNA, using `16` for the `power` argument like we determined above. +We will use the `blockwiseModules()` function to find gene co-expression modules in WGCNA, using `7` for the `power` argument like we determined above. This next step takes some time to run. The `blockwise` part of the `blockwiseModules()` function name refers to that these calculations will be done on chunks of your data at a time to help with conserving computing resources. @@ -425,7 +438,7 @@ operating system and other running programs. bwnet <- blockwiseModules(normalized_counts, maxBlockSize = 5000, # What size chunks (how many genes) the calculations should be run in TOMType = "signed", # topological overlap matrix - power = 16, # soft threshold for network construction + power = 7, # soft threshold for network construction numericLabels = TRUE, # Let's use numbers instead of colors for module labels randomSeed = 1234, # there's some randomness associated with this calculation # so we should set a seed @@ -444,7 +457,7 @@ We will save our whole results object to an RDS file in case we want to return t ```{r} readr::write_rds(bwnet, - file = file.path("results", "SRP133573_wgcna_results.RDS") + file = file.path("results", "SRP140558_wgcna_results.RDS") ) ``` @@ -473,8 +486,8 @@ all.equal(metadata$refinebio_accession_code, rownames(module_eigengenes)) ``` ```{r} -# Create the design matrix from the refinebio_treatment variable -des_mat <- model.matrix(~ metadata$refinebio_treatment) +# Create the design matrix from the `time_point` variable +des_mat <- model.matrix(~ metadata$time_point) ``` Run linear model on each module. @@ -503,21 +516,21 @@ They are sorted with the most significant results at the top. head(stats_df) ``` -Module 52 seems to be the most differentially expressed across `refinebio_treatment` groups. +Module 19 seems to be the most differentially expressed across `time_point` groups. Now we can do some investigation into this module. -## Let's make plot of module 52 +## Let's make plot of module 19 -As a sanity check, let's use `ggplot` to see what module 52's eigengene looks like between treatment groups. +As a sanity check, let's use `ggplot` to see what module 18's eigengene looks like between treatment groups. First we need to set up the module eigengene for this module with the sample metadata labels we need. ```{r} -module_52_df <- module_eigengenes %>% +module_19_df <- module_eigengenes %>% tibble::rownames_to_column("accession_code") %>% # Here we are performing an inner join with a subset of metadata dplyr::inner_join(metadata %>% - dplyr::select(refinebio_accession_code, refinebio_treatment), + dplyr::select(refinebio_accession_code, time_point), by = c("accession_code" = "refinebio_accession_code") ) ``` @@ -526,21 +539,24 @@ Now we are ready for plotting. ```{r} ggplot( - module_52_df, + module_19_df, aes( - x = refinebio_treatment, - y = ME52, - color = refinebio_treatment + x = time_point, + y = ME19, + color = time_point ) ) + - ggforce::geom_sina() + + # a boxplot with outlier points hidden (they will be in the sina plot) + geom_boxplot(width = 0.2, outlier.shape = NA) + + # A sina plot to show all of the individual data points + ggforce::geom_sina(maxwidth = 0.3) + theme_classic() ``` This makes sense! -Looks like module 52 has elevated expression post treatment. +Looks like module 19 has elevated expression during the acute illness but not when recovering. -## What genes are a part of module 52? +## What genes are a part of module 19? If you want to know which of your genes make up a modules, you can look at the `$colors` slot. This is a named list which associates the genes with the module they are a part of. @@ -552,18 +568,18 @@ gene_module_key <- tibble::enframe(bwnet$colors, name = "gene", value = "module" dplyr::mutate(module = paste0("ME", module)) ``` -Now we can find what genes are a part of module 52. +Now we can find what genes are a part of module 19. ```{r} gene_module_key %>% - dplyr::filter(module == "ME52") + dplyr::filter(module == "ME19") ``` Let's save this gene to module key to a TSV file for future use. ```{r} readr::write_tsv(gene_module_key, - file = file.path("results", "SRP133573_wgcna_gene_to_module.tsv") + file = file.path("results", "SRP140558_wgcna_gene_to_module.tsv") ) ``` @@ -581,9 +597,9 @@ make_module_heatmap <- function(module_name, # Create a summary heatmap of a given module. # # Args: - # module_name: a character indicating what module should be plotted, e.g. "ME52" + # module_name: a character indicating what module should be plotted, e.g. "ME19" # expression_mat: The full gene expression matrix. Default is `normalized_counts`. - # metadata_df: a data frame with refinebio_accession_code and refinebio_treatment + # metadata_df: a data frame with refinebio_accession_code and time_point # as columns. Default is `metadata`. # gene_module_key: a data.frame indicating what genes are a part of what modules. Default is `gene_module_key`. # module_eigengenes: a sample x eigengene data.frame with samples as rownames. Default is `module_eigengenes`. @@ -594,28 +610,28 @@ make_module_heatmap <- function(module_name, # Set up the module eigengene with its refinebio_accession_code module_eigengene <- module_eigengenes_df %>% - dplyr::select(module_name) %>% + dplyr::select(all_of(module_name)) %>% tibble::rownames_to_column("refinebio_accession_code") # Set up column annotation from metadata col_annot_df <- metadata_df %>% # Only select the treatment and sample ID columns - dplyr::select(refinebio_accession_code, refinebio_treatment) %>% + dplyr::select(refinebio_accession_code, time_point, refinebio_subject) %>% # Add on the eigengene expression by joining with sample IDs dplyr::inner_join(module_eigengene, by = "refinebio_accession_code") %>% - # Arrange by treatment - dplyr::arrange(refinebio_treatment, refinebio_accession_code) %>% + # Arrange by patient and time point + dplyr::arrange(time_point, refinebio_subject) %>% # Store sample tibble::column_to_rownames("refinebio_accession_code") # Create the ComplexHeatmap column annotation object col_annot <- ComplexHeatmap::HeatmapAnnotation( # Supply treatment labels - refinebio_treatment = col_annot_df$refinebio_treatment, + time_point = col_annot_df$time_point, # Add annotation barplot module_eigengene = ComplexHeatmap::anno_barplot(dplyr::select(col_annot_df, module_name)), - # Pick colors for each experimental group in refinebio_treatment - col = list(refinebio_treatment = c("post-adt" = "#f1a340", "pre-adt" = "#998ec3")) + # Pick colors for each experimental group in time_point + col = list(time_point = c("recovering" = "#f1a340", "acute illness" = "#998ec3")) ) # Get a vector of the Ensembl gene IDs that correspond to this module @@ -670,44 +686,43 @@ make_module_heatmap <- function(module_name, ## Make module heatmaps -Let's try out the custom heatmap function with module 52 (our most differentially expressed module). +Let's try out the custom heatmap function with module 19 (our most differentially expressed module). ```{r} -mod_52_heatmap <- make_module_heatmap(module_name = "ME52") +mod_19_heatmap <- make_module_heatmap(module_name = "ME19") # Print out the plot -mod_52_heatmap +mod_19_heatmap ``` -From the barplot portion of our plot, we can see `post-adt` samples have higher values for this eigengene for module 52. -In the heatmap portion, we can see how the individual genes that make up module 52 have more extreme values (very high or very low) in the `post-adt` samples. +From the barplot portion of our plot, we can see `acute illness` samples tend to have higher expression values for the module 19 eigengene. +In the heatmap portion, we can see how the individual genes that make up module 19 are overall higher than in the `recovering` samples. We can save this plot to PDF. ```{r} -pdf(file.path("results", "SRP133573_module_52_heatmap.pdf")) -mod_52_heatmap +pdf(file.path("results", "SRP140558_module_19_heatmap.pdf")) +mod_19_heatmap dev.off() ``` For comparison, let's try out the custom heatmap function with a different, _not_ differentially expressed module. ```{r} -mod_10_heatmap <- make_module_heatmap(module_name = "ME10") +mod_25_heatmap <- make_module_heatmap(module_name = "ME25") # Print out the plot -mod_10_heatmap +mod_25_heatmap ``` -In this non-significant module's heatmap, there's not a particularly strong pattern between pre and post ADT samples. -In general the expression of genes in module 10 does not vary much between groups, staying near the overall mean. -There are a few samples and some genes that show higher expression, but it is not surprising this does not results in a significant overall difference between the groups. +In this non-significant module's heatmap, there's not a particularly strong pattern between acute illness and recovery samples. +Though we can still see the genes in this module seem to be very correlated with each other (which is how we found them in the first place, so this makes sense!). Save this plot also. ```{r} -pdf(file.path("results", "SRP133573_module_10_heatmap.pdf")) -mod_10_heatmap +pdf(file.path("results", "SRP140558_module_25_heatmap.pdf")) +mod_25_heatmap dev.off() ``` @@ -725,7 +740,7 @@ This helps make your code more reproducible by recording what versions of softwa ```{r} # Print session info -sessionInfo() +sessioninfo::session_info() ``` # References diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html index b294fb8d..d0e555b4 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html @@ -3772,7 +3772,7 @@

      November 2020

      1 Purpose of this analysis

      -

      In this example, we use weighted gene co-expression network analysis (WGCNA) to identify co-expressed gene modules (Langfelder and Horvath 2008). WGCNA uses a series of correlations to identify sets of genes that are expressed together in your data set. This is a fairly intuitive approach to gene network analysis which can aid in interpretation of microarray & RNAseq data.

      +

      In this example, we use weighted gene co-expression network analysis (WGCNA) to identify co-expressed gene modules (Langfelder and Horvath 2008). WGCNA uses a series of correlations to identify sets of genes that are expressed together in your data set. This is a fairly intuitive approach to gene network analysis which can aid in interpretation of microarray & RNA-seq data.

      As output, WGCNA gives groups of co-expressed genes as well as an eigengene x sample matrix (where the values for each eigengene represent the summarized expression for a group of co-expressed genes) (Langfelder and Horvath 2007). This eigengene x sample data can, in many instances, be used as you would the original gene expression values. In this example, we use eigengene x sample data to identify differentially expressed modules between our treatment and control group

      This method does require some computing power, but can still be run locally (on your own computer) for most refine.bio datasets. As with many clustering and network methods, there are some parameters that may need tweaking.

      ⬇️ Jump to the analysis code ⬇️

      @@ -3815,7 +3815,7 @@

      2.2 Set up your analysis folders<

      2.3 Obtain the dataset from refine.bio

      For general information about downloading data for these examples, see our ‘Getting Started’ section.

      -

      Go to this dataset’s page on refine.bio.

      +

      Go to this dataset’s page on refine.bio.

      Click the “Download Now” button on the right side of this screen.

      Fill out the pop up window with your email and our Terms and Conditions:

      @@ -3826,7 +3826,7 @@

      2.3 Obtain the dataset from refin

      2.4 About the dataset we are using for this example

      -

      For this example analysis, we will use this prostate cancer dataset. The data that we downloaded from refine.bio for this analysis has 175 RNA-seq samples obtained from 20 patients with prostate cancer. Patients underwent androgen deprivation therapy (ADT) and RNA-seq samples include pre-ADT biopsies and post-ADT prostatectomy specimens.

      +

      For this example analysis, we will use this acute viral bronchiolitis dataset. The data that we downloaded from refine.bio for this analysis has 62 paired peripheral blood mononuclear cell RNA-seq samples obtained from 31 patients. Samples were collected at two time points: during their first, acute bronchiolitis visit (abbreviated “AV”) and their recovery, their post-convalescence visit (abbreviated “CV”).

      2.5 Place the dataset in your new data/ folder

      @@ -3834,7 +3834,7 @@

      2.5 Place the dataset in your new

      For more details on the contents of this folder see these docs on refine.bio.

      The <experiment_accession_id> folder has the data and metadata TSV files you will need for this example analysis. Experiment accession ids usually look something like GSE1235 or SRP12345.

      -

      Copy and paste the SRP133573 folder into your newly created data/ folder.

      +

      Copy and paste the SRP140558 folder into your newly created data/ folder.

      2.6 Check out our file structure!

      @@ -3844,7 +3844,7 @@

      2.6 Check out our file structure!
    • A folder called “data” which contains:
        -
      • The SRP133573 folder which contains: +
      • The SRP140558 folder which contains:
        • The gene expression
        • @@ -3860,13 +3860,13 @@

          2.6 Check out our file structure!

          In order for our example here to run without a hitch, we need these files to be in these locations so we’ve constructed a test to check before we get started with the analysis. These chunks will declare your file paths and double check that your files are in the right place.

          First we will declare our file paths to our data and metadata files, which should be in our data directory. This is handy to do because if we want to switch the dataset (see next section for more on this) we are using for this analysis, we will only have to change the file path here to get started.

          # Define the file path to the data directory
          -data_dir <- file.path("data", "SRP133573") # Replace with accession number which will be the name of the folder the files will be in
          +data_dir <- file.path("data", "SRP140558") # Replace with accession number which will be the name of the folder the files will be in
           
           # Declare the file path to the gene expression matrix file using the data directory saved as `data_dir`
          -data_file <- file.path(data_dir, "SRP133573.tsv") # Replace with file path to your dataset
          +data_file <- file.path(data_dir, "SRP140558.tsv") # Replace with file path to your dataset
           
           # Declare the file path to the metadata file using the data directory saved as `data_dir`
          -metadata_file <- file.path(data_dir, "metadata_SRP133573.tsv") # Replace with file path to your metadata
          +metadata_file <- file.path(data_dir, "metadata_SRP140558.tsv") # Replace with file path to your metadata

    • Now that our file paths are declared, we can use the file.exists() function to check that the files are where we specified above.

      # Check if the gene expression matrix file is at the file path stored in `data_file`
       file.exists(data_file)
      @@ -4029,19 +4029,16 @@

      4.2 Import and set up data

      # Read in metadata TSV file
       metadata <- readr::read_tsv(metadata_file)
      ## 
      -## ── Column specification ───────────────────────────────────────────────────────────────────────────────
      +## ── Column specification ──────────────────────────────────────────────────────────────
       ## cols(
      -##   .default = col_character(),
      -##   refinebio_age = col_logical(),
      -##   refinebio_cell_line = col_logical(),
      -##   refinebio_compound = col_logical(),
      -##   refinebio_disease_stage = col_logical(),
      -##   refinebio_genetic_information = col_logical(),
      -##   refinebio_processed = col_logical(),
      -##   refinebio_sex = col_logical(),
      -##   refinebio_source_archive_url = col_logical(),
      -##   refinebio_specimen_part = col_logical(),
      -##   refinebio_time = col_logical()
      +##   .default = col_logical(),
      +##   refinebio_accession_code = col_character(),
      +##   experiment_accession = col_character(),
      +##   refinebio_organism = col_character(),
      +##   refinebio_platform = col_character(),
      +##   refinebio_source_database = col_character(),
      +##   refinebio_subject = col_character(),
      +##   refinebio_title = col_character()
       ## )
       ## ℹ Use `spec()` for the full column specifications.
      # Read in data TSV file
      @@ -4049,7 +4046,7 @@ 

      4.2 Import and set up data

      # Here we are going to store the gene IDs as rownames so that we can have a numeric matrix to perform calculations on later tibble::column_to_rownames("Gene")
      ## 
      -## ── Column specification ───────────────────────────────────────────────────────────────────────────────
      +## ── Column specification ──────────────────────────────────────────────────────────────
       ## cols(
       ##   .default = col_double(),
       ##   Gene = col_character()
      @@ -4065,7 +4062,7 @@ 

      4.2 Import and set up data

      ## [1] TRUE

      4.2.1 Prepare data for DESeq2

      -

      There are two things we neeed to do to prep our expression data for DESeq2.

      +

      There are two things we need to do to prep our expression data for DESeq2.

      First, we need to make sure all of the values in our data are converted to integers as required by a DESeq2 function we will use later.

      Then, we need to filter out the genes that have not been expressed or that have low expression counts. This is recommended by WGCNA docs for RNA-seq data. Removing low count genes can also help improve your WGCNA results. We are going to do some pre-filtering to keep only genes with 50 or more reads in total across the samples.

      # The next DESeq2 functions need the values to be converted to integers
      @@ -4074,14 +4071,23 @@ 

      4.2.1 Prepare data for DESe as.data.frame() %>% # Only keep rows that have total counts above the cutoff dplyr::filter(rowSums(.) >= 50)

      -

      Another thing we need to do is make sure our main experimental group label is set up. In this case refinebio_treatment has two groups: pre-adt and post-adt. To keep these two treatments in logical (rather than alphabetical) order, we will convert this to a factor with pre-adt as the first level.

      +

      Another thing we need to do is set up our main experimental group variable. Unfortunately the metadata for this dataset are not set up into separate, neat columns, but we can accomplish that ourselves.

      +

      For this study, PBMCs were collected at two time points: during the patients’ first, acute bronchiolitis visit (abbreviated “AV”) and their recovery visit, (called post-convalescence and abbreviated “CV”).

      +

      For handier use of this information, we can create a new variable, time_point, that states this info more clearly. This new time_point variable will have two labels: acute illness and recovering based on the AV or CV coding located in the refinebio_title string variable.

      metadata <- metadata %>%
      -  dplyr::mutate(refinebio_treatment = factor(refinebio_treatment,
      -    levels = c("pre-adt", "post-adt")
      -  ))
      -

      Let’s double check that our factor set up is right.

      -
      levels(metadata$refinebio_treatment)
      -
      ## [1] "pre-adt"  "post-adt"
      + dplyr::mutate( + time_point = dplyr::case_when( + # Create our new variable based on refinebio_title containing AV/CV + stringr::str_detect(refinebio_title, "_AV_") ~ "acute illness", + stringr::str_detect(refinebio_title, "_CV_") ~ "recovering" + ), + # It's easier for future items if this is already set up as a factor + time_point = as.factor(time_point) + )

      +

      Let’s double check that our factor set up is right. We want acute illness to be the first level since it was the first time point collected.

      +
      levels(metadata$time_point)
      +
      ## [1] "acute illness" "recovering"
      +

      Great! We’re all set.

    @@ -4102,7 +4108,9 @@

    4.4 Perform DESeq2 normalization
    # Normalize and transform the data in the `DESeqDataSet` object using the `vst()`
     # function from the `DESEq2` R package
     dds_norm <- vst(dds)
    -

    At this point, if your data has any outliers, you should look into removing them as they can affect your WGCNA results. WGCNA’s tutorial has an example of exploring your data for outliers you can reference.

    +

    At this point, if your data set has any outlier samples, you should look into removing them as they can affect your WGCNA results.

    +

    WGCNA’s tutorial has an example of exploring your data for outliers you can reference.

    +

    For this example data set, we will skip this step (there are no obvious outliers) and proceed.

    4.5 Format normalized data for WGCNA

    @@ -4121,21 +4129,21 @@

    4.6 Determine parameters for WGCN )

    ## Warning: executing %dopar% sequentially: no parallel backend registered
    ##    Power SFT.R.sq  slope truncated.R.sq mean.k. median.k. max.k.
    -## 1      1  0.58200 12.200          0.957 13500.0   13600.0  15500
    -## 2      2  0.44500  5.130          0.972  7630.0    7650.0   9910
    -## 3      3  0.26300  2.570          0.985  4480.0    4450.0   6680
    -## 4      4  0.06480  0.914          0.985  2730.0    2680.0   4720
    -## 5      5  0.00662 -0.236          0.964  1720.0    1660.0   3450
    -## 6      6  0.15900 -1.010          0.965  1120.0    1060.0   2580
    -## 7      7  0.36500 -1.470          0.971   746.0     689.0   1980
    -## 8      8  0.50000 -1.730          0.972   509.0     459.0   1550
    -## 9      9  0.59700 -1.910          0.972   356.0     313.0   1220
    -## 10    10  0.67000 -2.060          0.973   253.0     217.0    982
    -## 11    12  0.74000 -2.260          0.970   135.0     110.0    651
    -## 12    14  0.79400 -2.320          0.978    76.9      58.6    447
    -## 13    16  0.82000 -2.350          0.981    45.9      32.7    315
    -## 14    18  0.83800 -2.360          0.985    28.6      18.9    227
    -## 15    20  0.84500 -2.350          0.987    18.5      11.2    167
    +## 1 1 0.0491 42.50 0.947 13400.0 13400.00 13600 +## 2 2 0.8530 -12.60 0.871 7230.0 7080.00 8430 +## 3 3 0.8800 -5.41 0.856 4120.0 3900.00 5840 +## 4 4 0.8910 -3.28 0.864 2470.0 2230.00 4340 +## 5 5 0.9060 -2.39 0.882 1560.0 1310.00 3380 +## 6 6 0.9140 -1.96 0.895 1030.0 798.00 2740 +## 7 7 0.9220 -1.72 0.908 706.0 496.00 2280 +## 8 8 0.9190 -1.58 0.910 504.0 314.00 1940 +## 9 9 0.9180 -1.48 0.917 371.0 203.00 1680 +## 10 10 0.9080 -1.42 0.915 282.0 134.00 1470 +## 11 12 0.9050 -1.34 0.927 174.0 60.40 1170 +## 12 14 0.8870 -1.31 0.927 116.0 28.60 964 +## 13 16 0.8660 -1.32 0.918 81.7 14.00 810 +## 14 18 0.8560 -1.33 0.921 59.7 7.13 692 +## 15 20 0.8570 -1.33 0.929 45.0 3.71 599

    This sft object has a lot of information, we will want to plot some of it to figure out what our power soft-threshold should be. We have to first calculate a measure of the model fit, the signed \(R^2\), and make that a new variable.

    sft_df <- data.frame(sft$fitIndices) %>%
       dplyr::mutate(model_fit = -sign(slope) * SFT.R.sq)
    @@ -4148,22 +4156,22 @@

    4.6 Determine parameters for WGCN # We will plot what WGCNA recommends as an R^2 cutoff geom_hline(yintercept = 0.80, col = "red") + # Just in case our values are low, we want to make sure we can still see the 0.80 level - ylim(c(min(sft_df$model_fit), 1)) + + ylim(c(min(sft_df$model_fit), 1.05)) + # We can add more sensible labels for our axis xlab("Soft Threshold (power)") + ylab("Scale Free Topology Model Fit, signed R^2") + ggtitle("Scale independence") + # This adds some nicer aesthetics to our plot theme_classic()

    -

    +

    Using this plot we can decide on a power parameter. WGCNA’s authors recommend using a power that has an signed \(R^2\) above 0.80, otherwise they warn your results may be too noisy to be meaningful.

    If you have multiple power values with signed \(R^2\) above 0.80, then picking the one at an inflection point, in other words where the \(R^2\) values seem to have reached their saturation (Zhang and Horvath 2005). You want to a power that gives you a big enough \(R^2\) but is not excessively large.

    -

    So using the plot above, going with a power soft-threshold of 16!

    +

    So using the plot above, going with a power soft-threshold of 7!

    If you find you have all very low \(R^2\) values this may be because there are too many genes with low expression values that are cluttering up the calculations. You can try returning to gene filtering step and choosing a more stringent cutoff (you’ll then need to re-run the transformation and subsequent steps to remake this plot to see if that helped).

    4.7 Run WGCNA!

    -

    We will use the blockwiseModules() function to find gene co-expression modules in WGCNA, using 16 for the power argument like we determined above.

    +

    We will use the blockwiseModules() function to find gene co-expression modules in WGCNA, using 7 for the power argument like we determined above.

    This next step takes some time to run. The blockwise part of the blockwiseModules() function name refers to that these calculations will be done on chunks of your data at a time to help with conserving computing resources.

    Here we are using the default maxBlockSize, 5000 but, you may want to adjust the maxBlockSize argument depending on your computer’s memory. The authors of WGCNA recommend running the largest block your computer can handle and they provide some approximations as to GB of memory of a laptop and what maxBlockSize it should be able to handle:

    @@ -4173,7 +4181,7 @@

    4.7 Run WGCNA!

    bwnet <- blockwiseModules(normalized_counts,
       maxBlockSize = 5000, # What size chunks (how many genes) the calculations should be run in
       TOMType = "signed", # topological overlap matrix
    -  power = 16, # soft threshold for network construction
    +  power = 7, # soft threshold for network construction
       numericLabels = TRUE, # Let's use numbers instead of colors for module labels
       randomSeed = 1234, # there's some randomness associated with this calculation
       # so we should set a seed
    @@ -4185,7 +4193,7 @@ 

    4.7 Run WGCNA!

    4.8 Write main WGCNA results object to file

    We will save our whole results object to an RDS file in case we want to return to our original WGCNA results.

    readr::write_rds(bwnet,
    -  file = file.path("results", "SRP133573_wgcna_results.RDS")
    +  file = file.path("results", "SRP140558_wgcna_results.RDS")
     )
    @@ -4198,7 +4206,7 @@

    4.9 Explore our WGCNA results

    head(module_eigengenes)
    @@ -4207,8 +4215,8 @@

    4.10 Which modules have biggest d

    We can also see if our eigengenes relate to our metadata labels. First we double check that our samples are still in order.

    all.equal(metadata$refinebio_accession_code, rownames(module_eigengenes))
    ## [1] TRUE
    -
    # Create the design matrix from the refinebio_treatment variable
    -des_mat <- model.matrix(~ metadata$refinebio_treatment)
    +
    # Create the design matrix from the `time_point` variable
    +des_mat <- model.matrix(~ metadata$time_point)

    Run linear model on each module. Limma wants our tests to be per row, so we also need to transpose so the eigengenes are rows

    # lmFit() needs a transposed version of the matrix
     fit <- limma::lmFit(t(module_eigengenes), design = des_mat)
    @@ -4224,53 +4232,56 @@ 

    4.10 Which modules have biggest d
    head(stats_df)
    -

    Module 52 seems to be the most differentially expressed across refinebio_treatment groups. Now we can do some investigation into this module.

    +

    Module 19 seems to be the most differentially expressed across time_point groups. Now we can do some investigation into this module.

    -
    -

    4.11 Let’s make plot of module 52

    -

    As a sanity check, let’s use ggplot to see what module 52’s eigengene looks like between treatment groups.

    +
    +

    4.11 Let’s make plot of module 19

    +

    As a sanity check, let’s use ggplot to see what module 18’s eigengene looks like between treatment groups.

    First we need to set up the module eigengene for this module with the sample metadata labels we need.

    -
    module_52_df <- module_eigengenes %>%
    +
    module_19_df <- module_eigengenes %>%
       tibble::rownames_to_column("accession_code") %>%
       # Here we are performing an inner join with a subset of metadata
       dplyr::inner_join(metadata %>%
    -    dplyr::select(refinebio_accession_code, refinebio_treatment),
    +    dplyr::select(refinebio_accession_code, time_point),
       by = c("accession_code" = "refinebio_accession_code")
       )

    Now we are ready for plotting.

    ggplot(
    -  module_52_df,
    +  module_19_df,
       aes(
    -    x = refinebio_treatment,
    -    y = ME52,
    -    color = refinebio_treatment
    +    x = time_point,
    +    y = ME19,
    +    color = time_point
       )
     ) +
    -  ggforce::geom_sina() +
    -  theme_classic()
    -

    -

    This makes sense! Looks like module 52 has elevated expression post treatment.

    + # a boxplot with outlier points hidden (they will be in the sina plot) + geom_boxplot(width = 0.2, outlier.shape = NA) + + # A sina plot to show all of the individual data points + ggforce::geom_sina(maxwidth = 0.3) + + theme_classic()
    +

    +

    This makes sense! Looks like module 19 has elevated expression during the acute illness but not when recovering.

    -
    -

    4.12 What genes are a part of module 52?

    +
    +

    4.12 What genes are a part of module 19?

    If you want to know which of your genes make up a modules, you can look at the $colors slot. This is a named list which associates the genes with the module they are a part of. We can turn this into a data frame for handy use.

    gene_module_key <- tibble::enframe(bwnet$colors, name = "gene", value = "module") %>%
       # Let's add the `ME` part so its more clear what these numbers are and it matches elsewhere
       dplyr::mutate(module = paste0("ME", module))
    -

    Now we can find what genes are a part of module 52.

    +

    Now we can find what genes are a part of module 19.

    gene_module_key %>%
    -  dplyr::filter(module == "ME52")
    + dplyr::filter(module == "ME19")

    Let’s save this gene to module key to a TSV file for future use.

    readr::write_tsv(gene_module_key,
    -  file = file.path("results", "SRP133573_wgcna_gene_to_module.tsv")
    +  file = file.path("results", "SRP140558_wgcna_gene_to_module.tsv")
     )
    @@ -4284,9 +4295,9 @@

    4.13 Make a custom heatmap functi # Create a summary heatmap of a given module. # # Args: - # module_name: a character indicating what module should be plotted, e.g. "ME52" + # module_name: a character indicating what module should be plotted, e.g. "ME19" # expression_mat: The full gene expression matrix. Default is `normalized_counts`. - # metadata_df: a data frame with refinebio_accession_code and refinebio_treatment + # metadata_df: a data frame with refinebio_accession_code and time_point # as columns. Default is `metadata`. # gene_module_key: a data.frame indicating what genes are a part of what modules. Default is `gene_module_key`. # module_eigengenes: a sample x eigengene data.frame with samples as rownames. Default is `module_eigengenes`. @@ -4297,28 +4308,28 @@

    4.13 Make a custom heatmap functi # Set up the module eigengene with its refinebio_accession_code module_eigengene <- module_eigengenes_df %>% - dplyr::select(module_name) %>% + dplyr::select(all_of(module_name)) %>% tibble::rownames_to_column("refinebio_accession_code") # Set up column annotation from metadata col_annot_df <- metadata_df %>% # Only select the treatment and sample ID columns - dplyr::select(refinebio_accession_code, refinebio_treatment) %>% + dplyr::select(refinebio_accession_code, time_point, refinebio_subject) %>% # Add on the eigengene expression by joining with sample IDs dplyr::inner_join(module_eigengene, by = "refinebio_accession_code") %>% - # Arrange by treatment - dplyr::arrange(refinebio_treatment, refinebio_accession_code) %>% + # Arrange by patient and time point + dplyr::arrange(time_point, refinebio_subject) %>% # Store sample tibble::column_to_rownames("refinebio_accession_code") # Create the ComplexHeatmap column annotation object col_annot <- ComplexHeatmap::HeatmapAnnotation( # Supply treatment labels - refinebio_treatment = col_annot_df$refinebio_treatment, + time_point = col_annot_df$time_point, # Add annotation barplot module_eigengene = ComplexHeatmap::anno_barplot(dplyr::select(col_annot_df, module_name)), - # Pick colors for each experimental group in refinebio_treatment - col = list(refinebio_treatment = c("post-adt" = "#f1a340", "pre-adt" = "#998ec3")) + # Pick colors for each experimental group in time_point + col = list(time_point = c("recovering" = "#f1a340", "acute illness" = "#998ec3")) ) # Get a vector of the Ensembl gene IDs that correspond to this module @@ -4372,32 +4383,32 @@

    4.13 Make a custom heatmap functi

    4.14 Make module heatmaps

    -

    Let’s try out the custom heatmap function with module 52 (our most differentially expressed module).

    -
    mod_52_heatmap <- make_module_heatmap(module_name = "ME52")
    +

    Let’s try out the custom heatmap function with module 19 (our most differentially expressed module).

    +
    mod_19_heatmap <- make_module_heatmap(module_name = "ME19")
    ## Note: Using an external vector in selections is ambiguous.
     ## ℹ Use `all_of(module_name)` instead of `module_name` to silence this message.
     ## ℹ See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
     ## This message is displayed once per session.
    # Print out the plot
    -mod_52_heatmap
    -

    -

    From the barplot portion of our plot, we can see post-adt samples have higher values for this eigengene for module 52. In the heatmap portion, we can see how the individual genes that make up module 52 have more extreme values (very high or very low) in the post-adt samples.

    +mod_19_heatmap
    +

    +

    From the barplot portion of our plot, we can see acute illness samples tend to have higher expression values for the module 19 eigengene. In the heatmap portion, we can see how the individual genes that make up module 19 are overall higher than in the recovering samples.

    We can save this plot to PDF.

    -
    pdf(file.path("results", "SRP133573_module_52_heatmap.pdf"))
    -mod_52_heatmap
    +
    pdf(file.path("results", "SRP140558_module_19_heatmap.pdf"))
    +mod_19_heatmap
     dev.off()
    ## png 
     ##   2

    For comparison, let’s try out the custom heatmap function with a different, not differentially expressed module.

    -
    mod_10_heatmap <- make_module_heatmap(module_name = "ME10")
    +
    mod_25_heatmap <- make_module_heatmap(module_name = "ME25")
     
     # Print out the plot
    -mod_10_heatmap
    -

    -

    In this non-significant module’s heatmap, there’s not a particularly strong pattern between pre and post ADT samples. In general the expression of genes in module 10 does not vary much between groups, staying near the overall mean. There are a few samples and some genes that show higher expression, but it is not surprising this does not results in a significant overall difference between the groups.

    +mod_25_heatmap
    +

    +

    In this non-significant module’s heatmap, there’s not a particularly strong pattern between acute illness and recovery samples. Though we can still see the genes in this module seem to be very correlated with each other (which is how we found them in the first place, so this makes sense!).

    Save this plot also.

    -
    pdf(file.path("results", "SRP133573_module_10_heatmap.pdf"))
    -mod_10_heatmap
    +
    pdf(file.path("results", "SRP140558_module_25_heatmap.pdf"))
    +mod_25_heatmap
     dev.off()
    ## png 
     ##   2
    @@ -4416,75 +4427,149 @@

    5 Resources for further learning<

    6 Session info

    At the end of every analysis, before saving your notebook, we recommend printing out your session info. This helps make your code more reproducible by recording what versions of software and packages you used to run this.

    # Print session info
    -sessionInfo()
    -
    ## R version 4.0.2 (2020-06-22)
    -## Platform: x86_64-pc-linux-gnu (64-bit)
    -## Running under: Ubuntu 20.04 LTS
    +sessioninfo::session_info()
    +
    ## ─ Session info ───────────────────────────────────────────────────────────────
    +##  setting  value                       
    +##  version  R version 4.0.2 (2020-06-22)
    +##  os       Ubuntu 20.04 LTS            
    +##  system   x86_64, linux-gnu           
    +##  ui       X11                         
    +##  language (EN)                        
    +##  collate  en_US.UTF-8                 
    +##  ctype    en_US.UTF-8                 
    +##  tz       Etc/UTC                     
    +##  date     2020-11-25                  
     ## 
    -## Matrix products: default
    -## BLAS/LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.8.so
    +## ─ Packages ───────────────────────────────────────────────────────────────────
    +##  package              * version  date       lib source        
    +##  annotate               1.68.0   2020-10-27 [1] Bioconductor  
    +##  AnnotationDbi          1.52.0   2020-10-27 [1] Bioconductor  
    +##  assertthat             0.2.1    2019-03-21 [1] RSPM (R 4.0.0)
    +##  backports              1.1.10   2020-09-15 [1] RSPM (R 4.0.2)
    +##  base64enc              0.1-3    2015-07-28 [1] RSPM (R 4.0.0)
    +##  Biobase              * 2.50.0   2020-10-27 [1] Bioconductor  
    +##  BiocGenerics         * 0.36.0   2020-10-27 [1] Bioconductor  
    +##  BiocParallel           1.24.1   2020-11-06 [1] Bioconductor  
    +##  bit                    4.0.4    2020-08-04 [1] RSPM (R 4.0.2)
    +##  bit64                  4.0.5    2020-08-30 [1] RSPM (R 4.0.2)
    +##  bitops                 1.0-6    2013-08-17 [1] RSPM (R 4.0.0)
    +##  blob                   1.2.1    2020-01-20 [1] RSPM (R 4.0.0)
    +##  Cairo                  1.5-12.2 2020-07-07 [1] RSPM (R 4.0.2)
    +##  checkmate              2.0.0    2020-02-06 [1] RSPM (R 4.0.0)
    +##  circlize               0.4.10   2020-06-15 [1] RSPM (R 4.0.0)
    +##  cli                    2.1.0    2020-10-12 [1] RSPM (R 4.0.2)
    +##  clue                   0.3-57   2019-02-25 [1] RSPM (R 4.0.0)
    +##  cluster                2.1.0    2019-06-19 [1] RSPM (R 4.0.0)
    +##  codetools              0.2-16   2018-12-24 [2] CRAN (R 4.0.2)
    +##  colorspace             1.4-1    2019-03-18 [1] RSPM (R 4.0.0)
    +##  ComplexHeatmap         2.6.0    2020-10-27 [1] Bioconductor  
    +##  crayon                 1.3.4    2017-09-16 [1] RSPM (R 4.0.0)
    +##  data.table             1.13.0   2020-07-24 [1] RSPM (R 4.0.2)
    +##  DBI                    1.1.0    2019-12-15 [1] RSPM (R 4.0.0)
    +##  DelayedArray           0.16.0   2020-10-27 [1] Bioconductor  
    +##  DESeq2               * 1.30.0   2020-10-27 [1] Bioconductor  
    +##  digest                 0.6.25   2020-02-23 [1] RSPM (R 4.0.0)
    +##  doParallel             1.0.15   2019-08-02 [1] RSPM (R 4.0.0)
    +##  dplyr                  1.0.2    2020-08-18 [1] RSPM (R 4.0.2)
    +##  dynamicTreeCut       * 1.63-1   2016-03-11 [1] RSPM (R 4.0.0)
    +##  ellipsis               0.3.1    2020-05-15 [1] RSPM (R 4.0.0)
    +##  evaluate               0.14     2019-05-28 [1] RSPM (R 4.0.0)
    +##  fansi                  0.4.1    2020-01-08 [1] RSPM (R 4.0.0)
    +##  farver                 2.0.3    2020-01-16 [1] RSPM (R 4.0.0)
    +##  fastcluster          * 1.1.25   2018-06-07 [1] RSPM (R 4.0.0)
    +##  foreach                1.5.0    2020-03-30 [1] RSPM (R 4.0.0)
    +##  foreign                0.8-80   2020-05-24 [2] CRAN (R 4.0.2)
    +##  Formula                1.2-3    2018-05-03 [1] RSPM (R 4.0.0)
    +##  genefilter             1.72.0   2020-10-27 [1] Bioconductor  
    +##  geneplotter            1.68.0   2020-10-27 [1] Bioconductor  
    +##  generics               0.0.2    2018-11-29 [1] RSPM (R 4.0.0)
    +##  GenomeInfoDb         * 1.26.0   2020-10-27 [1] Bioconductor  
    +##  GenomeInfoDbData       1.2.4    2020-11-09 [1] Bioconductor  
    +##  GenomicRanges        * 1.42.0   2020-10-27 [1] Bioconductor  
    +##  getopt                 1.20.3   2019-03-22 [1] RSPM (R 4.0.0)
    +##  GetoptLong             1.0.3    2020-10-01 [1] RSPM (R 4.0.2)
    +##  ggforce                0.3.2    2020-06-23 [1] RSPM (R 4.0.2)
    +##  ggplot2              * 3.3.2    2020-06-19 [1] RSPM (R 4.0.1)
    +##  GlobalOptions          0.1.2    2020-06-10 [1] RSPM (R 4.0.0)
    +##  glue                   1.4.2    2020-08-27 [1] RSPM (R 4.0.2)
    +##  GO.db                  3.12.1   2020-11-09 [1] Bioconductor  
    +##  gridExtra              2.3      2017-09-09 [1] RSPM (R 4.0.0)
    +##  gtable                 0.3.0    2019-03-25 [1] RSPM (R 4.0.0)
    +##  Hmisc                  4.4-1    2020-08-10 [1] RSPM (R 4.0.2)
    +##  hms                    0.5.3    2020-01-08 [1] RSPM (R 4.0.0)
    +##  htmlTable              2.1.0    2020-09-16 [1] RSPM (R 4.0.2)
    +##  htmltools              0.5.0    2020-06-16 [1] RSPM (R 4.0.1)
    +##  htmlwidgets            1.5.2    2020-10-03 [1] RSPM (R 4.0.2)
    +##  httr                   1.4.2    2020-07-20 [1] RSPM (R 4.0.2)
    +##  impute                 1.64.0   2020-10-27 [1] Bioconductor  
    +##  IRanges              * 2.24.0   2020-10-27 [1] Bioconductor  
    +##  iterators              1.0.12   2019-07-26 [1] RSPM (R 4.0.0)
    +##  jpeg                   0.1-8.1  2019-10-24 [1] RSPM (R 4.0.0)
    +##  jsonlite               1.7.1    2020-09-07 [1] RSPM (R 4.0.2)
    +##  knitr                  1.30     2020-09-22 [1] RSPM (R 4.0.2)
    +##  labeling               0.3      2014-08-23 [1] RSPM (R 4.0.0)
    +##  lattice                0.20-41  2020-04-02 [2] CRAN (R 4.0.2)
    +##  latticeExtra           0.6-29   2019-12-19 [1] RSPM (R 4.0.0)
    +##  lifecycle              0.2.0    2020-03-06 [1] RSPM (R 4.0.0)
    +##  limma                  3.46.0   2020-10-27 [1] Bioconductor  
    +##  locfit                 1.5-9.4  2020-03-25 [1] RSPM (R 4.0.0)
    +##  magick                 2.4.0    2020-06-23 [1] RSPM (R 4.0.2)
    +##  magrittr             * 1.5      2014-11-22 [1] RSPM (R 4.0.0)
    +##  MASS                   7.3-51.6 2020-04-26 [2] CRAN (R 4.0.2)
    +##  Matrix                 1.2-18   2019-11-27 [2] CRAN (R 4.0.2)
    +##  MatrixGenerics       * 1.2.0    2020-10-27 [1] Bioconductor  
    +##  matrixStats          * 0.57.0   2020-09-25 [1] RSPM (R 4.0.2)
    +##  memoise                1.1.0    2017-04-21 [1] RSPM (R 4.0.0)
    +##  munsell                0.5.0    2018-06-12 [1] RSPM (R 4.0.0)
    +##  nnet                   7.3-14   2020-04-26 [2] CRAN (R 4.0.2)
    +##  optparse             * 1.6.6    2020-04-16 [1] RSPM (R 4.0.0)
    +##  pillar                 1.4.6    2020-07-10 [1] RSPM (R 4.0.2)
    +##  pkgconfig              2.0.3    2019-09-22 [1] RSPM (R 4.0.0)
    +##  png                    0.1-7    2013-12-03 [1] RSPM (R 4.0.0)
    +##  polyclip               1.10-0   2019-03-14 [1] RSPM (R 4.0.0)
    +##  preprocessCore         1.52.0   2020-10-27 [1] Bioconductor  
    +##  ps                     1.4.0    2020-10-07 [1] RSPM (R 4.0.2)
    +##  purrr                  0.3.4    2020-04-17 [1] RSPM (R 4.0.0)
    +##  R.cache                0.14.0   2019-12-06 [1] RSPM (R 4.0.0)
    +##  R.methodsS3            1.8.1    2020-08-26 [1] RSPM (R 4.0.2)
    +##  R.oo                   1.24.0   2020-08-26 [1] RSPM (R 4.0.2)
    +##  R.utils                2.10.1   2020-08-26 [1] RSPM (R 4.0.2)
    +##  R6                     2.4.1    2019-11-12 [1] RSPM (R 4.0.0)
    +##  RColorBrewer           1.1-2    2014-12-07 [1] RSPM (R 4.0.0)
    +##  Rcpp                   1.0.5    2020-07-06 [1] RSPM (R 4.0.2)
    +##  RCurl                  1.98-1.2 2020-04-18 [1] RSPM (R 4.0.0)
    +##  readr                  1.4.0    2020-10-05 [1] RSPM (R 4.0.2)
    +##  rematch2               2.1.2    2020-05-01 [1] RSPM (R 4.0.0)
    +##  rjson                  0.2.20   2018-06-08 [1] RSPM (R 4.0.0)
    +##  rlang                  0.4.8    2020-10-08 [1] RSPM (R 4.0.2)
    +##  rmarkdown              2.4      2020-09-30 [1] RSPM (R 4.0.2)
    +##  rpart                  4.1-15   2019-04-12 [2] CRAN (R 4.0.2)
    +##  RSQLite                2.2.1    2020-09-30 [1] RSPM (R 4.0.2)
    +##  rstudioapi             0.11     2020-02-07 [1] RSPM (R 4.0.0)
    +##  S4Vectors            * 0.28.0   2020-10-27 [1] Bioconductor  
    +##  scales                 1.1.1    2020-05-11 [1] RSPM (R 4.0.0)
    +##  sessioninfo            1.1.1    2018-11-05 [1] RSPM (R 4.0.0)
    +##  shape                  1.4.5    2020-09-13 [1] RSPM (R 4.0.2)
    +##  stringi                1.5.3    2020-09-09 [1] RSPM (R 4.0.2)
    +##  stringr                1.4.0    2019-02-10 [1] RSPM (R 4.0.0)
    +##  styler                 1.3.2    2020-02-23 [1] RSPM (R 4.0.0)
    +##  SummarizedExperiment * 1.20.0   2020-10-27 [1] Bioconductor  
    +##  survival               3.1-12   2020-04-10 [2] CRAN (R 4.0.2)
    +##  tibble                 3.0.4    2020-10-12 [1] RSPM (R 4.0.2)
    +##  tidyselect             1.1.0    2020-05-11 [1] RSPM (R 4.0.0)
    +##  tweenr                 1.0.1    2018-12-14 [1] RSPM (R 4.0.2)
    +##  vctrs                  0.3.4    2020-08-29 [1] RSPM (R 4.0.2)
    +##  WGCNA                * 1.69     2020-02-28 [1] RSPM (R 4.0.2)
    +##  withr                  2.3.0    2020-09-22 [1] RSPM (R 4.0.2)
    +##  xfun                   0.18     2020-09-29 [1] RSPM (R 4.0.2)
    +##  XML                    3.99-0.5 2020-07-23 [1] RSPM (R 4.0.2)
    +##  xtable                 1.8-4    2019-04-21 [1] RSPM (R 4.0.0)
    +##  XVector                0.30.0   2020-10-27 [1] Bioconductor  
    +##  yaml                   2.2.1    2020-02-01 [1] RSPM (R 4.0.0)
    +##  zlibbioc               1.36.0   2020-10-27 [1] Bioconductor  
     ## 
    -## locale:
    -##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
    -##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
    -##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=C             
    -##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
    -##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
    -## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
    -## 
    -## attached base packages:
    -## [1] parallel  stats4    stats     graphics  grDevices utils     datasets 
    -## [8] methods   base     
    -## 
    -## other attached packages:
    -##  [1] ggplot2_3.3.2               WGCNA_1.69                 
    -##  [3] fastcluster_1.1.25          dynamicTreeCut_1.63-1      
    -##  [5] magrittr_1.5                DESeq2_1.30.0              
    -##  [7] SummarizedExperiment_1.20.0 Biobase_2.50.0             
    -##  [9] MatrixGenerics_1.2.0        matrixStats_0.57.0         
    -## [11] GenomicRanges_1.42.0        GenomeInfoDb_1.26.0        
    -## [13] IRanges_2.24.0              S4Vectors_0.28.0           
    -## [15] BiocGenerics_0.36.0         optparse_1.6.6             
    -## 
    -## loaded via a namespace (and not attached):
    -##   [1] colorspace_1.4-1       rjson_0.2.20           ellipsis_0.3.1        
    -##   [4] circlize_0.4.10        htmlTable_2.1.0        XVector_0.30.0        
    -##   [7] GlobalOptions_0.1.2    base64enc_0.1-3        clue_0.3-57           
    -##  [10] rstudioapi_0.11        farver_2.0.3           getopt_1.20.3         
    -##  [13] bit64_4.0.5            AnnotationDbi_1.52.0   fansi_0.4.1           
    -##  [16] codetools_0.2-16       splines_4.0.2          R.methodsS3_1.8.1     
    -##  [19] doParallel_1.0.15      impute_1.64.0          geneplotter_1.68.0    
    -##  [22] knitr_1.30             polyclip_1.10-0        jsonlite_1.7.1        
    -##  [25] Formula_1.2-3          Cairo_1.5-12.2         annotate_1.68.0       
    -##  [28] cluster_2.1.0          GO.db_3.12.1           png_0.1-7             
    -##  [31] R.oo_1.24.0            ggforce_0.3.2          readr_1.4.0           
    -##  [34] compiler_4.0.2         httr_1.4.2             backports_1.1.10      
    -##  [37] assertthat_0.2.1       Matrix_1.2-18          limma_3.46.0          
    -##  [40] cli_2.1.0              tweenr_1.0.1           htmltools_0.5.0       
    -##  [43] tools_4.0.2            gtable_0.3.0           glue_1.4.2            
    -##  [46] GenomeInfoDbData_1.2.4 dplyr_1.0.2            Rcpp_1.0.5            
    -##  [49] styler_1.3.2           vctrs_0.3.4            preprocessCore_1.52.0 
    -##  [52] iterators_1.0.12       xfun_0.18              stringr_1.4.0         
    -##  [55] ps_1.4.0               lifecycle_0.2.0        XML_3.99-0.5          
    -##  [58] MASS_7.3-51.6          zlibbioc_1.36.0        scales_1.1.1          
    -##  [61] hms_0.5.3              rematch2_2.1.2         RColorBrewer_1.1-2    
    -##  [64] ComplexHeatmap_2.6.0   yaml_2.2.1             memoise_1.1.0         
    -##  [67] gridExtra_2.3          rpart_4.1-15           latticeExtra_0.6-29   
    -##  [70] stringi_1.5.3          RSQLite_2.2.1          genefilter_1.72.0     
    -##  [73] foreach_1.5.0          checkmate_2.0.0        BiocParallel_1.24.1   
    -##  [76] shape_1.4.5            rlang_0.4.8            pkgconfig_2.0.3       
    -##  [79] bitops_1.0-6           evaluate_0.14          lattice_0.20-41       
    -##  [82] purrr_0.3.4            htmlwidgets_1.5.2      labeling_0.3          
    -##  [85] bit_4.0.4              tidyselect_1.1.0       R6_2.4.1              
    -##  [88] magick_2.4.0           generics_0.0.2         Hmisc_4.4-1           
    -##  [91] DelayedArray_0.16.0    DBI_1.1.0              pillar_1.4.6          
    -##  [94] foreign_0.8-80         withr_2.3.0            survival_3.1-12       
    -##  [97] RCurl_1.98-1.2         nnet_7.3-14            tibble_3.0.4          
    -## [100] crayon_1.3.4           rmarkdown_2.4          GetoptLong_1.0.3      
    -## [103] jpeg_0.1-8.1           locfit_1.5-9.4         grid_4.0.2            
    -## [106] data.table_1.13.0      blob_1.2.1             digest_0.6.25         
    -## [109] xtable_1.8-4           R.cache_0.14.0         R.utils_2.10.1        
    -## [112] munsell_0.5.0
    +## [1] /usr/local/lib/R/site-library +## [2] /usr/local/lib/R/library

    References

    diff --git a/components/dictionary.txt b/components/dictionary.txt index 2290522d..ae78912d 100644 --- a/components/dictionary.txt +++ b/components/dictionary.txt @@ -14,6 +14,7 @@ bioinformatics Brainarray Brainarray’s Brems +bronchiolitis CCDL CCDL's cDNA @@ -26,6 +27,7 @@ Cmd ColorBrewer Compara ComplexHeatmap +ComplexHeatmap's CREB Crouser cytosolic @@ -89,6 +91,7 @@ maxBlockSize medulloblastoma microarray’s molecularly +mononuclear musculus MSigDB myeloid @@ -100,6 +103,7 @@ orthologs orthology overexpressing overexpression +PBMCs permutated permutating pheatmap From 2dd67384eeff1f5390fb8a9dfe08ca4fb0106a74 Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Mon, 30 Nov 2020 15:12:34 -0500 Subject: [PATCH 48/50] Change pdf -> png and rereun (#382) --- .../network-analysis_rnaseq_01_wgcna.Rmd | 6 ++--- .../network-analysis_rnaseq_01_wgcna.html | 26 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd index fda3c87f..53e0198d 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.Rmd @@ -698,10 +698,10 @@ mod_19_heatmap From the barplot portion of our plot, we can see `acute illness` samples tend to have higher expression values for the module 19 eigengene. In the heatmap portion, we can see how the individual genes that make up module 19 are overall higher than in the `recovering` samples. -We can save this plot to PDF. +We can save this plot to PNG. ```{r} -pdf(file.path("results", "SRP140558_module_19_heatmap.pdf")) +png(file.path("results", "SRP140558_module_19_heatmap.png")) mod_19_heatmap dev.off() ``` @@ -721,7 +721,7 @@ Though we can still see the genes in this module seem to be very correlated with Save this plot also. ```{r} -pdf(file.path("results", "SRP140558_module_25_heatmap.pdf")) +png(file.path("results", "SRP140558_module_25_heatmap.png")) mod_25_heatmap dev.off() ``` diff --git a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html index d0e555b4..f9bde0f5 100644 --- a/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html +++ b/04-advanced-topics/network-analysis_rnaseq_01_wgcna.html @@ -4029,7 +4029,7 @@

    4.2 Import and set up data

    # Read in metadata TSV file
     metadata <- readr::read_tsv(metadata_file)
    ## 
    -## ── Column specification ──────────────────────────────────────────────────────────────
    +## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_logical(),
     ##   refinebio_accession_code = col_character(),
    @@ -4046,7 +4046,7 @@ 

    4.2 Import and set up data

    # Here we are going to store the gene IDs as rownames so that we can have a numeric matrix to perform calculations on later tibble::column_to_rownames("Gene")
    ## 
    -## ── Column specification ──────────────────────────────────────────────────────────────
    +## ── Column specification ─────────────────────────────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_double(),
     ##   Gene = col_character()
    @@ -4262,7 +4262,7 @@ 

    4.11 Let’s make plot of module # A sina plot to show all of the individual data points ggforce::geom_sina(maxwidth = 0.3) + theme_classic()

    -

    +

    This makes sense! Looks like module 19 has elevated expression during the acute illness but not when recovering.

    @@ -4391,10 +4391,10 @@

    4.14 Make module heatmaps

    ## This message is displayed once per session.
    # Print out the plot
     mod_19_heatmap
    -

    +

    From the barplot portion of our plot, we can see acute illness samples tend to have higher expression values for the module 19 eigengene. In the heatmap portion, we can see how the individual genes that make up module 19 are overall higher than in the recovering samples.

    -

    We can save this plot to PDF.

    -
    pdf(file.path("results", "SRP140558_module_19_heatmap.pdf"))
    +

    We can save this plot to PNG.

    +
    png(file.path("results", "SRP140558_module_19_heatmap.png"))
     mod_19_heatmap
     dev.off()
    ## png 
    @@ -4404,10 +4404,10 @@ 

    4.14 Make module heatmaps

    # Print out the plot mod_25_heatmap
    -

    +

    In this non-significant module’s heatmap, there’s not a particularly strong pattern between acute illness and recovery samples. Though we can still see the genes in this module seem to be very correlated with each other (which is how we found them in the first place, so this makes sense!).

    Save this plot also.

    -
    pdf(file.path("results", "SRP140558_module_25_heatmap.pdf"))
    +
    png(file.path("results", "SRP140558_module_25_heatmap.png"))
     mod_25_heatmap
     dev.off()
    ## png 
    @@ -4438,7 +4438,7 @@ 

    6 Session info

    ## collate en_US.UTF-8 ## ctype en_US.UTF-8 ## tz Etc/UTC -## date 2020-11-25 +## date 2020-11-30 ## ## ─ Packages ─────────────────────────────────────────────────────────────────── ## package * version date lib source @@ -4462,7 +4462,7 @@

    6 Session info

    ## cluster 2.1.0 2019-06-19 [1] RSPM (R 4.0.0) ## codetools 0.2-16 2018-12-24 [2] CRAN (R 4.0.2) ## colorspace 1.4-1 2019-03-18 [1] RSPM (R 4.0.0) -## ComplexHeatmap 2.6.0 2020-10-27 [1] Bioconductor +## ComplexHeatmap 2.6.2 2020-11-12 [1] Bioconductor ## crayon 1.3.4 2017-09-16 [1] RSPM (R 4.0.0) ## data.table 1.13.0 2020-07-24 [1] RSPM (R 4.0.2) ## DBI 1.1.0 2019-12-15 [1] RSPM (R 4.0.0) @@ -4483,8 +4483,8 @@

    6 Session info

    ## genefilter 1.72.0 2020-10-27 [1] Bioconductor ## geneplotter 1.68.0 2020-10-27 [1] Bioconductor ## generics 0.0.2 2018-11-29 [1] RSPM (R 4.0.0) -## GenomeInfoDb * 1.26.0 2020-10-27 [1] Bioconductor -## GenomeInfoDbData 1.2.4 2020-11-09 [1] Bioconductor +## GenomeInfoDb * 1.26.1 2020-11-20 [1] Bioconductor +## GenomeInfoDbData 1.2.4 2020-11-25 [1] Bioconductor ## GenomicRanges * 1.42.0 2020-10-27 [1] Bioconductor ## getopt 1.20.3 2019-03-22 [1] RSPM (R 4.0.0) ## GetoptLong 1.0.3 2020-10-01 [1] RSPM (R 4.0.2) @@ -4492,7 +4492,7 @@

    6 Session info

    ## ggplot2 * 3.3.2 2020-06-19 [1] RSPM (R 4.0.1) ## GlobalOptions 0.1.2 2020-06-10 [1] RSPM (R 4.0.0) ## glue 1.4.2 2020-08-27 [1] RSPM (R 4.0.2) -## GO.db 3.12.1 2020-11-09 [1] Bioconductor +## GO.db 3.12.1 2020-11-25 [1] Bioconductor ## gridExtra 2.3 2017-09-09 [1] RSPM (R 4.0.0) ## gtable 0.3.0 2019-03-25 [1] RSPM (R 4.0.0) ## Hmisc 4.4-1 2020-08-10 [1] RSPM (R 4.0.2) From 7c7555a8f8e117eab877d258a97b26990349bc6c Mon Sep 17 00:00:00 2001 From: Chante Bethell <43576623+cbethell@users.noreply.github.com> Date: Mon, 30 Nov 2020 17:25:30 -0500 Subject: [PATCH 49/50] Pr 2 of 2: Add Microarray Pathway Analysis - GSVA example (#362) * Mechanics for CSS file and navbar add feedback URL (#303) * Adding in some style with css * Use css magic * Try making the navbar blue * Add survey link * Make font smaller * Need a comma * Change to normalizePath * normalizepath separate step references.bib * Move references.bib to component folder * Made ccs modifications, added logo file Made changes to css/navbar.html Tried to add the logo but it but it cuts out and not sure how to make it decent. * Resolve render-notebooks.R conflict * Remove testing html from file diff * uncommented mobile nav Co-authored-by: dvenprasad * Making staging changes live (#329) * Adding in some style with css * Use css magic * Try making the navbar blue * Add survey link * Make font smaller * Need a comma * Change to normalizePath * normalizepath separate step references.bib * Move references.bib to component folder * Update github actions to reflect staging branch (#311) * Update github actions to reflect staging branch * Add libglpk40 to Dockerfile * Make it gh-pages-stages! * Remove dockerfile change that should have been on its own all along * Does this work? * Declare a uses * Switch how env is declared * Force it to run so we can test it * try no curly brackets * What's up with the branch * Move to bash if instead * Need quotes? * forgot a `then` * Try dollar signs * Doesn't like the `.`? * Use curly brackets * Try ${GITHUB_REF} * Try ${BRANCH_NAME} * try ${GITHUB_REF#refs/*/} * use jashapiro suggestion * Change to base ref * Change back to `github.ref` * Get rid of PR `on:` * Try another test * Docker dep fix: Add lib package 40 thing that clusterprofiler needs (#316) * Add lib package 40 thing that clusterprofiler needs * Try adding options(warn = 2) * Test if options(warn =2) means it breaks like it should * Revert "Test if options(warn =2) means it breaks like it should" This reverts commit d9f688f68448ef69fe4c1caa48af23051cd7f4e3. * Revert "Try another test" This reverts commit 845cf1aff92ea7b83f402bbefd563562b44e5eac. * Add google analytics to renderings (#314) * Try adding google analytics * Add to header using includes * temporary file snuck in there * Restore master version so they aren't in the review * Let's call an html file and html file * Docker dep fix: Add lib package 40 thing that clusterprofiler needs (#316) * Add lib package 40 thing that clusterprofiler needs * Try adding options(warn = 2) * Test if options(warn =2) means it breaks like it should * Revert "Test if options(warn =2) means it breaks like it should" This reverts commit d9f688f68448ef69fe4c1caa48af23051cd7f4e3. * Only push if we are in master. For simplicity, we will now run this even if the dockerfile hasn't changed. * Add test target * test staging workflow with this branch * back to latest tag * Try separate push step * change tags to test push * Revert "change tags to test push" This reverts commit 6a38574d312cee82c90c3c036ac9033f9af7f7ec. * Remove this branch from triggers * Push staging, retag and push master Okay, so the branch name is now inaccurate, but that is fine... * Made ccs modifications, added logo file Made changes to css/navbar.html Tried to add the logo but it but it cuts out and not sure how to make it decent. * Resolve render-notebooks.R conflict * Remove testing html from file diff * uncommented mobile nav * Update scripts/render-notebooks.R * Add some issue templates (#319) * Add some rough draft issue templates * Incorporate cbethell review * Get rid of `Other` labels that aren't useful * Update diagrams showing how microarray/RNA-seq work (#326) * Mechanics for CSS file and navbar add feedback URL (#303) * Adding in some style with css * Use css magic * Try making the navbar blue * Add survey link * Make font smaller * Need a comma * Change to normalizePath * normalizepath separate step references.bib * Move references.bib to component folder * Made ccs modifications, added logo file Made changes to css/navbar.html Tried to add the logo but it but it cuts out and not sure how to make it decent. * Resolve render-notebooks.R conflict * Remove testing html from file diff * uncommented mobile nav Co-authored-by: dvenprasad * Update microarray and RNAseq overview figures - add context re figures - change .jpg to .png for consistency * Revert "Mechanics for CSS file and navbar add feedback URL (#303)" This reverts commit 8b81fdd96eeecf1d0e479d7908376b8e57dc356d. * update links to diagrams * @dvenprasad updated figure spacing * add the right updated figure * replace section of link to figures with updated commit id * incorporate @cansavvy's suggested changes Co-authored-by: Candace Savonen Co-authored-by: dvenprasad Co-authored-by: Joshua Shapiro Co-authored-by: dvenprasad Co-authored-by: Chante Bethell <43576623+cbethell@users.noreply.github.com> * Add part two of GSVA microarray example notebook * update comment * update violin plot and its interpretation * add to `dictionary.txt` * apply significance and multiple hypothesis testing before plotting * Switching to northcott and a sina plot of one pathway * Style Rmds * Re-render it all * Adjust wording add tidbits about limma and re-render * Few more wording edits * Caught a few more little wording issues. Re-rendered * Remove Murat2008 ref * Restore the part 1 changes that got lost in the merge * incorporate most of jaclyn-taroni's suggested changes - create annotated results df using wide -> long method - update some wording/context re `mx.diff = TRUE` and what that means * remove outdated entries in `dictionary.txt` - remove unnecessary reference in `references.bib` * fix axis label * break up `annotated_results_df` steps * Apply suggestions from code review Co-authored-by: Jaclyn Taroni * add reminder of `gsva_results` format - cite gsva package vignette - add more detail around "appropriate format" for plotting Co-authored-by: Candace Savonen Co-authored-by: dvenprasad Co-authored-by: Joshua Shapiro Co-authored-by: GitHub Actions Co-authored-by: Jaclyn Taroni --- .../pathway-analysis_microarray_03_gsva.Rmd | 320 ++++++++++-- .../pathway-analysis_microarray_03_gsva.html | 478 ++++++++++++++---- components/dictionary.txt | 1 + components/references.bib | 7 + 4 files changed, 673 insertions(+), 133 deletions(-) diff --git a/02-microarray/pathway-analysis_microarray_03_gsva.Rmd b/02-microarray/pathway-analysis_microarray_03_gsva.Rmd index 31d8c51e..8f61c2aa 100644 --- a/02-microarray/pathway-analysis_microarray_03_gsva.Rmd +++ b/02-microarray/pathway-analysis_microarray_03_gsva.Rmd @@ -20,6 +20,7 @@ This means that GSVA scores will depend on the samples included in the dataset w GSVA determines the relative enrichment of gene sets across samples using a non-parametric approach. GSVA transforms a gene by sample gene expression matrix into a gene set by sample pathway enrichment matrix [@Hanzelmann-github]. +You can use these scores for other downstream analyses; in this analysis we will perform differential expression to determine what pathway is most different across our variable of interest. ⬇️ [**Jump to the analysis code**](#analysis) ⬇️ @@ -74,7 +75,7 @@ In the same place you put this `.Rmd` file, you should now have three new empty For general information about downloading data for these examples, see our ['Getting Started' section](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#how-to-get-the-data). -Go to this [dataset's page on refine.bio](https://www.refine.bio/experiments/GSE7696/glioblastoma-from-a-homogenous-cohort-of-patients-treated-within-clinical-trial). +Go to this [dataset's page on refine.bio](https://www.refine.bio/experiments/GSE37382). Click the "Download Now" button on the right side of this screen. @@ -89,9 +90,10 @@ You will get an email when it is ready. ## About the dataset we are using for this example -For this example analysis, we will use this [glioblastoma dataset](https://www.refine.bio/experiments/GSE7696/glioblastoma-from-a-homogenous-cohort-of-patients-treated-within-clinical-trial). - -This dataset contains the measured microarray gene expression of 79 glioblastoma samples from a homogenous cohort of clinical patients. +For this example analysis, we will use this [medulloblastoma dataset](https://www.refine.bio/experiments/GSE37382) [@Northcott2012]. +The data that we downloaded from refine.bio for this analysis has 285 microarray samples obtained from patients with medulloblastoma. +Medulloblastoma is the most common childhood brain cancer and is often categorized by subgroups. +We will use these `subgroup` labels from our metadata to perform differential expression with our GSVA scores. ## Place the dataset in your new `data/` folder @@ -103,10 +105,10 @@ Double clicking should unzip this for you and create a folder of the same name. For more details on the contents of this folder see [these docs on refine.bio](http://docs.refine.bio/en/latest/main_text.html#downloadable-files). -The `GSE7696` folder has the data and metadata TSV files you will need for this example analysis. +The `GSE37382` folder has the data and metadata TSV files you will need for this example analysis. Experiment accession ids usually look something like `GSE1235` or `SRP12345`. -Copy and paste the `GSE7696` folder into your newly created `data/` folder. +Copy and paste the `GSE37382` folder into your newly created `data/` folder. ## Check out our file structure! @@ -114,12 +116,12 @@ Your new analysis folder should contain: - The example analysis `.Rmd` you downloaded - A folder called "data" which contains: - - The `GSE7696` folder which contains: + - The `GSE37382` folder which contains: - The gene expression - The metadata TSV - A folder for `plots` (currently empty) - A folder for `results` (currently empty) - + Your example analysis folder should now look something like this (except with respective experiment accession ID and analysis notebook name you are using): @@ -132,13 +134,13 @@ This is handy to do because if we want to switch the dataset (see next section f ```{r} # Define the file path to the data directory -data_dir <- file.path("data", "GSE7696") # Replace with accession number which will be the name of the folder the files will be in +data_dir <- file.path("data", "GSE37382") # Replace with accession number which will be the name of the folder the files will be in # Declare the file path to the gene expression matrix file using the data directory saved as `data_dir` -data_file <- file.path(data_dir, "GSE7696.tsv") # Replace with file path to your dataset +data_file <- file.path(data_dir, "GSE37382.tsv") # Replace with file path to your dataset # Declare the file path to the metadata file using the data directory saved as `data_dir` -metadata_file <- file.path(data_dir, "metadata_GSE7696.tsv") # Replace with file path to your metadata +metadata_file <- file.path(data_dir, "metadata_GSE37382.tsv") # Replace with file path to your metadata ``` Now that our file paths are declared, we can use the `file.exists()` function to check that the files are where we specified above. @@ -171,10 +173,12 @@ From here you can customize this analysis example to fit your own scientific que See our Getting Started page with [instructions for package installation](https://alexslemonade.github.io/refinebio-examples/01-getting-started/getting-started.html#what-you-need-to-install) for a list of the other software you will need, as well as more tips and resources. -In this analysis, we will be using the [`GSVA`](https://www.bioconductor.org/packages/release/bioc/html/GSVA.html) package to perform GSVA and the [`qusage`](https://www.bioconductor.org/packages/release/bioc/html/qusage.html) package to read in the GMT file containing the gene set data [@Hanzelmann2013; @Meng2019]. +In this analysis, we will be using the [`GSVA`](https://www.bioconductor.org/packages/release/bioc/html/GSVA.html) package to perform GSVA and the [`qusage`](https://www.bioconductor.org/packages/release/bioc/html/qusage.html) package to read in the GMT file containing the gene set data [@Hanzelmann2013; @Yaari2013]. We will also need the [`org.Hs.eg.db`](https://bioconductor.org/packages/release/data/annotation/html/org.Hs.eg.db.html) package to perform gene identifier conversion [@Carlson2020-human]. +We'll also be performing differential expression test on our GSVA scores, and for that we will use `limma` [@Ritchie2015] and we'll make a sina plot of the scores of our most significant pathway using a ggplot2 companion package, `ggforce`. + ```{r} if (!("GSVA" %in% installed.packages())) { # Install this package if it isn't installed yet @@ -190,6 +194,16 @@ if (!("org.Hs.eg.db" %in% installed.packages())) { # Install this package if it isn't installed yet BiocManager::install("org.Hs.eg.db", update = FALSE) } + +if (!("limma" %in% installed.packages())) { + # Install this package if it isn't installed yet + BiocManager::install("limma", update = FALSE) +} + +if (!("ggforce" %in% installed.packages())) { + # Install this package if it isn't installed yet + install.packages("ggforce") +} ``` Attach the packages we need for this analysis. @@ -204,6 +218,9 @@ library(GSVA) # Human annotation package we'll use for gene identifier conversion library(org.Hs.eg.db) +# Attach the ggplot2 package for plotting +library(ggplot2) + # We will need this so we can use the pipe: %>% library(magrittr) ``` @@ -220,24 +237,18 @@ We stored our file paths as objects named `metadata_file` and `data_file` in [th metadata <- readr::read_tsv(metadata_file) # Read in data TSV file -expression_df <- readr::read_tsv(data_file) %>% - # Tuck away the gene ID column as row names - tibble::column_to_rownames("Gene") +expression_df <- readr::read_tsv(data_file) ``` -Let's ensure that the metadata and data are in the same sample order. +Let’s ensure that the metadata and data are in the same sample order. ```{r} # Make the data in the order of the metadata expression_df <- expression_df %>% - dplyr::select(metadata$geo_accession) + dplyr::select(c(Gene, metadata$geo_accession)) # Check if this is in the same order -all.equal(colnames(expression_df), metadata$geo_accession) - -# Bring back the "Gene" column in preparation for mapping -expression_df <- expression_df %>% - tibble::rownames_to_column("Gene") +all.equal(colnames(expression_df)[-1], metadata$geo_accession) ``` ### Import Gene Sets @@ -307,9 +318,7 @@ mapped_df <- data.frame( # Make an `Ensembl` column to store the row names tibble::rownames_to_column("Ensembl") %>% # Now let's join the rest of the expression data - dplyr::inner_join(expression_df, by = c("Ensembl" = "Gene")) %>% - # We won't be using Ensembl IDs moving forward, so we will drop this column - dplyr::select(-Ensembl) + dplyr::inner_join(expression_df, by = c("Ensembl" = "Gene")) ``` This `1:many mapping between keys and columns` message means that some Ensembl gene identifiers map to multiple Entrez IDs. @@ -356,15 +365,15 @@ mapped_df %>% dplyr::filter(entrez_id %in% dup_entrez_ids) ``` -As an example using the strategy we described, for `GSM187153`'s data in the first column, `-0.007355525` is larger than `-0.136553967` so moving forward, Entrez gene `6013` will have `-0.007355525` value and the `-0.136553967` would be dropped from the dataset. - +As an example using the strategy we described, for `GSM917111`'s data in the first column, `0.2294387` is larger than `0.1104345` so moving forward, Entrez gene `6013` will have `0.2294387` value and the `0.1104345` would be dropped from the dataset. However, this is just one method of handling duplicate gene identifiers. See the [Gene Set Enrichment Analysis (GSEA) User guide](https://www.gsea-msigdb.org/gsea/doc/GSEAUserGuideFrame.html) for more information on other expression values that can be used, like the median expression value for example [@GSEA-user-guide]. - Now, let's implement our choose the max value method for all samples and Entrez IDs using tidyverse functions. ```{r} max_dup_df <- mapped_df %>% + # We won't be using Ensembl IDs moving forward, so we will drop this column + dplyr::select(-Ensembl) %>% # Filter to include only the rows associated with the duplicate Entrez gene identifiers dplyr::filter(entrez_id %in% dup_entrez_ids) %>% # Group by Entrez IDs @@ -376,20 +385,21 @@ max_dup_df <- mapped_df %>% max_dup_df ``` -We can see `GSM187153` now has the `-0.007355525` value for Entrez ID `6013` like expected. - +We can see `GSM917111` now has the `0.2294387` value for Entrez ID `6013` like expected. Looks like we were able to successfully get rid of the duplicate Entrez gene identifiers! Now let's combine our de-duplicated data with the rest of the mapped data! ```{r} filtered_mapped_df <- mapped_df %>% + # We won't be using Ensembl IDs moving forward, so we will drop this column + dplyr::select(-Ensembl) %>% # First let's get the data associated with the Entrez gene identifiers that aren't duplicated dplyr::filter(!entrez_id %in% dup_entrez_ids) %>% # Now let's bind the rows of the maximum expression data we stored in `max_dup_df` dplyr::bind_rows(max_dup_df) ``` - + As mentioned earlier, we need a matrix for GSVA. Let's now convert our data frame into a matrix and prepare our object for GSVA. @@ -405,11 +415,255 @@ Note that if we had duplicate gene identifiers here, we would not be able to set ## GSVA - Microarray -_Addressed in upcoming PR_ +Rather than ranking genes based on some gene-level statistic selected by the user, GSVA fits a model and ranks genes based on their expression level relative to the sample distribution. +The pathway-level score calculated is a way of asking how genes _within_ a gene set vary as compared to genes that are _outside_ of that gene set [@Malhotra2018]. + +The idea here is that we will get pathway-level scores for each sample that indicate if genes in a pathway vary concordantly in one direction (over-expressed or under-expressed relative to the overall population) [@Hanzelmann2013]. + +The output is a gene set by sample matrix of GSVA scores. + +### Perform GSVA + +Let's perform GSVA using the `gsva()` function. +See `?gsva` for more options. + +```{r} +gsva_results <- gsva( + filtered_mapped_matrix, + hallmarks_list, + method = "gsva", + # Appropriate for our log2-transformed microarray data + kcdf = "Gaussian", + # Minimum gene set size + min.sz = 15, + # Maximum gene set size + max.sz = 500, + # Compute Gaussian-distributed scores + mx.diff = TRUE, + # Don't print out the progress bar + verbose = FALSE +) +``` + +Let's explore what the output of `gsva()` looks like. + +```{r} +head(gsva_results[, 1:10]) +``` + +## Find differentially expressed pathways + +If we want to identify most differentially expressed pathways across subgroups, we can use functionality in the `limma` package to test the GSVA scores. +This is one approach for working with GSVA scores. +The `mx.diff = TRUE` argument that we supplied to the `gsva()` function in the previous section means the GSVA output scores should be normally distributed, which allows downstream analyses that make this assumption about the distribution [@Hanzelmann-gsva-vignette]. + +### Create the design matrix + +`limma` needs a numeric design matrix to signify which samples are of which subtype of medulloblastoma. +Now we will create a model matrix based on our `subgroup` variable. +We are using a `+ 0` in the model which sets the intercept to 0 so the subgroup effects capture expression for that group, rather than difference from the first group. +If you have a control group, you might want that to be the intercept. + +```{r} +# Create the design matrix +des_mat <- model.matrix(~ metadata$subgroup + 0) +``` + +Let's take a look at the design matrix we created. + +```{r} +# Print out the design matrix +head(des_mat) +``` + +The design matrix column names are a bit messy, so we will neaten them up by dropping the `metadata$subgroup` designation they all have and for being able to reference them easily later, we want to drop spaces as well. + +```{r} +# Make the column names less messy +colnames(des_mat) <- stringr::str_remove(colnames(des_mat), "metadata\\$subgroup") + +# Do a similar thing but remove spaces in names +colnames(des_mat) <- stringr::str_remove(colnames(des_mat), " ") +``` + +Side note: If you are wondering why there are two `\` above in `"filtered_metadata\\$subgroup"`, that's called an [escape character](https://cran.r-project.org/web/packages/stringr/vignettes/regular-expressions.html#escaping). +There's a whole universe of things called [regular expressions (regex)](https://cran.r-project.org/web/packages/stringr/vignettes/regular-expressions.html) that can be super handy for string manipulations. + +## Perform differential expression on pathway scores + +Run the linear model on each pathway (each row of `gsva_results`). + +```{r} +# Apply linear model to data +fit <- limma::lmFit(gsva_results, design = des_mat) + +# Apply empirical Bayes to smooth standard errors +fit <- limma::eBayes(fit) +``` + +Now that we have our basic model fitting, we will want to make the contrasts among all our groups. +Depending on your scientific questions, you will need to customize the next steps. +Consulting the [limma users guide](https://www.bioconductor.org/packages/devel/bioc/vignettes/limma/inst/doc/usersguide.pdf) for how to set up your model based on your hypothesis is a good idea. + +In this contrasts matrix, we are comparing each subgroup to the average of the other subgroups. +We're dividing by two in this expression so that each group is compared to the average of the other two groups (`makeContrasts()` doesn't allow you to use functions like `mean()`; it wants a formula). + +```{r} +contrast_matrix <- makeContrasts( + "G3vsOther" = Group3 - (Group4 + SHH) / 2, + "G4vsOther" = Group4 - (Group3 + SHH) / 2, + "SHHvsOther" = SHH - (Group3 + Group4) / 2, + levels = des_mat +) +``` + +Side note: If you did have a control group you wanted to compare each group to, you could make each contrast to that control group, so the formulate would look like `Group3 = Group3 - Control` for each one. +We highly recommend consulting the [limma users guide](https://bioconductor.org/packages/release/bioc/vignettes/limma/inst/doc/usersguide.pdf) for figuring out what your `makeContrasts()` and `model.matrix()` setups should look like [@Ritchie2015]. + +Now that we have the contrasts matrix set up, we can use it to re-fit the model and re-smooth it with `eBayes()`. + +```{r} +# Fit the model according to the contrasts matrix +contrasts_fit <- contrasts.fit(fit, contrast_matrix) + +# Re-smooth the Bayes +contrasts_fit <- eBayes(contrasts_fit) +``` + +Here's a [nifty article and example](http://varianceexplained.org/r/empirical_bayes_baseball/) about what the empirical Bayes smoothing is for [@bayes-estimates]. + +Now let's create the results table based on the contrasts fitted model. + +This step will provide the Benjamini-Hochberg multiple testing correction. +The `topTable()` function default is to use Benjamini-Hochberg but this can be changed to a different method using the `adjust.method` argument (see the `?topTable` help page for more about the options). + +```{r} +# Apply multiple testing correction and obtain stats +stats_df <- topTable(contrasts_fit, number = nrow(expression_df)) %>% + tibble::rownames_to_column("Gene") +``` + +Let's take a peek at our results table. + +```{r} +head(stats_df) +``` + +For each gene, each group's fold change in expression, compared to the average of the other groups is reported. + +By default, results are ordered from largest `F` value to the smallest, which means your most differentially expressed genes across all groups should be toward the top. + +This means `HALLMARK_UNFOLDED_PROTEIN_RESPONSE` appears to be the pathway that contains the most significant distribution of scores across subgroups. + +## Visualizing Results + +Let's make a plot for our most significant pathway, `HALLMARK_UNFOLDED_PROTEIN_RESPONSE`. + +### Sina plot + +First we need to get our GSVA scores for this pathway into a long data frame, an appropriate format for `ggplot2`. + +Let's look at the current format of `gsva_results`. + +```{r} +head(gsva_results[, 1:10]) +``` + +We can see that they are in a wide format with the gsva scores for each sample spread across a row associated with each pathway. + +Now let's convert these results into a data frame and into a long format, using the `tidyr::pivot_longer()` function. + +```{r} +annotated_results_df <- gsva_results %>% + # Make this into a data frame + data.frame() %>% + # Gene set names are row names + tibble::rownames_to_column("pathway") %>% + # Get into long format using the `tidyr::pivot_longer()` function + tidyr::pivot_longer( + cols = -pathway, + names_to = "sample", + values_to = "gsva_score" + ) + +# Preview the annotated results object +head(annotated_results_df) +``` + +Now let's filter to include only the scores associated with our most significant pathway, `HALLMARK_UNFOLDED_PROTEIN_RESPONSE`, and join the relevant group labels from the metadata for plotting. + +```{r} +top_pathway_annotated_results_df <- annotated_results_df %>% + # Filter for only scores associated with our most significant pathway + dplyr::filter(pathway == "HALLMARK_UNFOLDED_PROTEIN_RESPONSE") %>% + # Join the column with the group labels that we would like to plot and compare -- + # Select the variables relevant to your data + dplyr::left_join(metadata %>% dplyr::select( + refinebio_accession_code, + subgroup + ), + # Tell the join what columns are equivalent and should be used as a key + by = c("sample" = "refinebio_accession_code") + ) + +# Preview the filtered annotated results object +head(top_pathway_annotated_results_df) +``` + +Now let's make a sina plot so we can look at the differences between the `subgroup` groups using our GSVA scores. + +```{r} +# Sina plot comparing GSVA scores for `HALLMARK_UNFOLDED_PROTEIN_RESPONSE` the `subgroup` groups in our dataset +sina_plot <- + ggplot( + top_pathway_annotated_results_df, # Supply our annotated data frame + aes( + x = subgroup, # Replace with a grouping variable relevant to your data + y = gsva_score, # Column we created to store the GSVA scores in the last chunk + color = subgroup # Let's make the groups different colors too + ) + ) + + # Add a boxplot that will have summary stats + geom_boxplot(outlier.shape = NA) + + # Make a sina plot that shows individual values + ggforce::geom_sina() + + # Rename the y-axis label + labs(y = "HALLMARK_UNFOLDED_PROTEIN_RESPONSE_score") + + # Adjust the plot background for better visualization + theme_bw() + +# Display plot +sina_plot +``` + +Looks like the `Group 4` samples have lower GSVA scores for `HALLMARK_UNFOLDED_PROTEIN_RESPONSE` as compared to the `SHH` and `Group 3` scores. + +Let's save this plot to PNG. + +```{r} +ggsave(file.path(plots_dir, "GSE37382_gsva_HALLMARK_UNFOLDED_PROTEIN_RESPONSE_sina_plot.png"), + plot = sina_plot +) +``` + +## Write results to file + +Now let's write all of our GSVA results to file. + +```{r} +gsva_results %>% + as.data.frame() %>% + tibble::rownames_to_column("pathway") %>% + readr::write_tsv(file.path( + results_dir, + "GSE37382_gsva_results.tsv" + )) +``` # Resources for further learning -_Addressed in upcoming PR_ +- [GSVA Paper](https://bmcbioinformatics.biomedcentral.com/articles/10.1186/1471-2105-14-7) [@Hanzelmann2013] +- See this article on [Decoding Gene Set Variation Analysis](https://towardsdatascience.com/decoding-gene-set-variation-analysis-8193a0cfda3) [@Malhotra2018] # Session info diff --git a/02-microarray/pathway-analysis_microarray_03_gsva.html b/02-microarray/pathway-analysis_microarray_03_gsva.html index baf4b7fd..1ae4f1b1 100644 --- a/02-microarray/pathway-analysis_microarray_03_gsva.html +++ b/02-microarray/pathway-analysis_microarray_03_gsva.html @@ -3742,7 +3742,7 @@ @@ -3774,7 +3774,7 @@

    November 2020

    1 Purpose of this analysis

    This example is one of pathway analysis module set, we recommend looking at the pathway analysis introduction to help you determine which pathway analysis method is best suited for your purposes.

    In this example we will cover a method called Gene Set Variation Analysis (GSVA) to calculate gene set or pathway scores on a per-sample basis. Gene set variation analysis (GSVA) constitutes a starting point to build pathway-centric models of biology. Rather than contextualizing some results you have received from another analysis like DGE, GSVA is designed to provide an estimate of pathway variation for each of the samples in an experiment. This means that GSVA scores will depend on the samples included in the dataset when you run GSVA; if you added more samples and ran GSVA again, you would expect the scores to change (Hänzelmann et al. 2013a).

    -

    GSVA determines the relative enrichment of gene sets across samples using a non-parametric approach. GSVA transforms a gene by sample gene expression matrix into a gene set by sample pathway enrichment matrix (Hänzelmann et al. 2013b).

    +

    GSVA determines the relative enrichment of gene sets across samples using a non-parametric approach. GSVA transforms a gene by sample gene expression matrix into a gene set by sample pathway enrichment matrix (Hänzelmann et al. 2013b). You can use these scores for other downstream analyses; in this analysis we will perform differential expression to determine what pathway is most different across our variable of interest.

    ⬇️ Jump to the analysis code ⬇️

    @@ -3815,7 +3815,7 @@

    2.2 Set up your analysis folders<

    2.3 Obtain the dataset from refine.bio

    For general information about downloading data for these examples, see our ‘Getting Started’ section.

    -

    Go to this dataset’s page on refine.bio.

    +

    Go to this dataset’s page on refine.bio.

    Click the “Download Now” button on the right side of this screen.

    Fill out the pop up window with your email and our Terms and Conditions:

    @@ -3824,16 +3824,15 @@

    2.3 Obtain the dataset from refin

    2.4 About the dataset we are using for this example

    -

    For this example analysis, we will use this glioblastoma dataset.

    -

    This dataset contains the measured microarray gene expression of 79 glioblastoma samples from a homogenous cohort of clinical patients.

    +

    For this example analysis, we will use this medulloblastoma dataset (Northcott et al. 2012). The data that we downloaded from refine.bio for this analysis has 285 microarray samples obtained from patients with medulloblastoma. Medulloblastoma is the most common childhood brain cancer and is often categorized by subgroups. We will use these subgroup labels from our metadata to perform differential expression with our GSVA scores.

    2.5 Place the dataset in your new data/ folder

    refine.bio will send you a download button in the email when it is ready. Follow the prompt to download a zip file that has a name with a series of letters and numbers and ends in .zip. Double clicking should unzip this for you and create a folder of the same name.

    For more details on the contents of this folder see these docs on refine.bio.

    -

    The GSE7696 folder has the data and metadata TSV files you will need for this example analysis. Experiment accession ids usually look something like GSE1235 or SRP12345.

    -

    Copy and paste the GSE7696 folder into your newly created data/ folder.

    +

    The GSE37382 folder has the data and metadata TSV files you will need for this example analysis. Experiment accession ids usually look something like GSE1235 or SRP12345.

    +

    Copy and paste the GSE37382 folder into your newly created data/ folder.

    2.6 Check out our file structure!

    @@ -3843,7 +3842,7 @@

    2.6 Check out our file structure!
  • A folder called “data” which contains:
      -
    • The GSE7696 folder which contains: +
    • The GSE37382 folder which contains:
      • The gene expression
      • @@ -3860,13 +3859,13 @@

        2.6 Check out our file structure!

        In order for our example here to run without a hitch, we need these files to be in these locations so we’ve constructed a test to check before we get started with the analysis. These chunks will declare your file paths and double check that your files are in the right place.

        First we will declare our file paths to our data and metadata files, which should be in our data directory. This is handy to do because if we want to switch the dataset (see next section for more on this) we are using for this analysis, we will only have to change the file path here to get started.

        # Define the file path to the data directory
        -data_dir <- file.path("data", "GSE7696") # Replace with accession number which will be the name of the folder the files will be in
        +data_dir <- file.path("data", "GSE37382") # Replace with accession number which will be the name of the folder the files will be in
         
         # Declare the file path to the gene expression matrix file using the data directory saved as `data_dir`
        -data_file <- file.path(data_dir, "GSE7696.tsv") # Replace with file path to your dataset
        +data_file <- file.path(data_dir, "GSE37382.tsv") # Replace with file path to your dataset
         
         # Declare the file path to the metadata file using the data directory saved as `data_dir`
        -metadata_file <- file.path(data_dir, "metadata_GSE7696.tsv") # Replace with file path to your metadata
        +metadata_file <- file.path(data_dir, "metadata_GSE37382.tsv") # Replace with file path to your metadata

  • Now that our file paths are declared, we can use the file.exists() function to check that the files are where we specified above.

    # Check if the gene expression matrix file is at the file path stored in `data_file`
     file.exists(data_file)
    @@ -3890,8 +3889,9 @@

    4 Gene set variation analysis - M

    4.1 Install libraries

    See our Getting Started page with instructions for package installation for a list of the other software you will need, as well as more tips and resources.

    -

    In this analysis, we will be using the GSVA package to perform GSVA and the qusage package to read in the GMT file containing the gene set data (Hänzelmann et al. 2013a; Meng et al. 2019).

    +

    In this analysis, we will be using the GSVA package to perform GSVA and the qusage package to read in the GMT file containing the gene set data (Hänzelmann et al. 2013a; Yaari et al. 2013).

    We will also need the org.Hs.eg.db package to perform gene identifier conversion (Carlson 2020).

    +

    We’ll also be performing differential expression test on our GSVA scores, and for that we will use limma (Ritchie et al. 2015) and we’ll make a sina plot of the scores of our most significant pathway using a ggplot2 companion package, ggforce.

    if (!("GSVA" %in% installed.packages())) {
       # Install this package if it isn't installed yet
       BiocManager::install("GSVA", update = FALSE)
    @@ -3905,7 +3905,17 @@ 

    4.1 Install libraries

    if (!("org.Hs.eg.db" %in% installed.packages())) { # Install this package if it isn't installed yet BiocManager::install("org.Hs.eg.db", update = FALSE) -}
    +} + +if (!("limma" %in% installed.packages())) { + # Install this package if it isn't installed yet + BiocManager::install("limma", update = FALSE) +} + +if (!("ggforce" %in% installed.packages())) { + # Install this package if it isn't installed yet + install.packages("ggforce") +}

    Attach the packages we need for this analysis.

    # Attach the `qusage` library
     library(qusage)
    @@ -3954,8 +3964,11 @@

    4.1 Install libraries

    ## ## expand.grid
    ## 
    -
    # We will need this so we can use the pipe: %>%
    -library(magrittr)
    +
    # Attach the ggplot2 package for plotting
    +library(ggplot2)
    +
    +# We will need this so we can use the pipe: %>%
    +library(magrittr)

    4.2 Import and set up data

    @@ -3964,33 +3977,32 @@

    4.2 Import and set up data

    # Read in metadata TSV file
     metadata <- readr::read_tsv(metadata_file)
    ## 
    -## ── Column specification ─────────────────────────────────────────────────────────────────────
    +## ── Column specification ──────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_character(),
     ##   refinebio_age = col_double(),
     ##   refinebio_cell_line = col_logical(),
     ##   refinebio_compound = col_logical(),
    +##   refinebio_disease = col_logical(),
     ##   refinebio_disease_stage = col_logical(),
     ##   refinebio_genetic_information = col_logical(),
     ##   refinebio_processed = col_logical(),
     ##   refinebio_race = col_logical(),
     ##   refinebio_source_archive_url = col_logical(),
    +##   refinebio_specimen_part = col_logical(),
    +##   refinebio_subject = col_logical(),
     ##   refinebio_time = col_logical(),
    -##   age = col_double(),
    +##   refinebio_treatment = col_logical(),
     ##   channel_count = col_double(),
     ##   `contact_zip/postal_code` = col_double(),
     ##   data_row_count = col_double(),
    -##   `survival status` = col_double(),
    -##   `survival time in months` = col_double(),
     ##   taxid_ch1 = col_double()
     ## )
     ## ℹ Use `spec()` for the full column specifications.
    # Read in data TSV file
    -expression_df <- readr::read_tsv(data_file) %>%
    -  # Tuck away the gene ID  column as row names
    -  tibble::column_to_rownames("Gene")
    +expression_df <- readr::read_tsv(data_file)
    ## 
    -## ── Column specification ─────────────────────────────────────────────────────────────────────
    +## ── Column specification ──────────────────────────────────────────────────────────────────
     ## cols(
     ##   .default = col_double(),
     ##   Gene = col_character()
    @@ -3999,27 +4011,24 @@ 

    4.2 Import and set up data

    Let’s ensure that the metadata and data are in the same sample order.

    # Make the data in the order of the metadata
     expression_df <- expression_df %>%
    -  dplyr::select(metadata$geo_accession)
    +  dplyr::select(c(Gene, metadata$geo_accession))
     
     # Check if this is in the same order
    -all.equal(colnames(expression_df), metadata$geo_accession)
    +all.equal(colnames(expression_df)[-1], metadata$geo_accession)
    ## [1] TRUE
    -
    # Bring back the "Gene" column in preparation for mapping
    -expression_df <- expression_df %>%
    -  tibble::rownames_to_column("Gene")

    4.2.1 Import Gene Sets

    The function that we will use to run GSVA wants the gene sets to be in a list, rather than a tidy data frame.

    We are therefore going to read in the Hallmark collection of gene sets file directly from MSigDB, rather than using the msigdbr package like we did in earlier notebooks (Dolgalev 2020).

    Note that when reading in the Hallmark collection file in this manner, the data is only compatible with Homo sapiens datasets.

    -
    # R can often read in data from a URL
    -hallmarks_url <- "https://data.broadinstitute.org/gsea-msigdb/msigdb/release/7.2/h.all.v7.2.entrez.gmt"
    -
    -# QuSAGE is another pathway analysis method, the `qusage` package has a function
    -# for reading GMT files and turning them into a list
    -hallmarks_list <- qusage::read.gmt(hallmarks_url)
    +
    # R can often read in data from a URL
    +hallmarks_url <- "https://data.broadinstitute.org/gsea-msigdb/msigdb/release/7.2/h.all.v7.2.entrez.gmt"
    +
    +# QuSAGE is another pathway analysis method, the `qusage` package has a function
    +# for reading GMT files and turning them into a list
    +hallmarks_list <- qusage::read.gmt(hallmarks_url)

    What does this hallmarks_list look like?

    -
    head(hallmarks_list)
    +
    head(hallmarks_list)
    ## $HALLMARK_TNFA_SIGNALING_VIA_NFKB
     ##   [1] "3726"   "2920"   "467"    "4792"   "7128"   "5743"   "2919"   "8870"  
     ##   [9] "9308"   "6364"   "2921"   "23764"  "4791"   "7127"   "1839"   "1316"  
    @@ -4135,7 +4144,7 @@ 

    4.2.2 Gene identifier conversion<

    We’re going to convert our identifiers in expression_df to Entrez IDs, but you can, with the change of a single argument, use the same code to convert to many other types of identifiers!

    The annotation package org.Hs.eg.db contains information for different identifiers (Carlson 2020). org.Hs.eg.db is specific to Homo sapiens – this is what the Hs in the package name is referencing.

    We can see what types of IDs are available to us in an annotation package with keytypes().

    -
    keytypes(org.Hs.eg.db)
    +
    keytypes(org.Hs.eg.db)
    ##  [1] "ACCNUM"       "ALIAS"        "ENSEMBL"      "ENSEMBLPROT"  "ENSEMBLTRANS"
     ##  [6] "ENTREZID"     "ENZYME"       "EVIDENCE"     "EVIDENCEALL"  "GENENAME"    
     ## [11] "GO"           "GOALL"        "IPI"          "MAP"          "OMIM"        
    @@ -4146,106 +4155,347 @@ 

    4.2.2 Gene identifier conversion<

    Take a look at our other gene identifier conversion examples for examples with different species and gene ID types: the microarray example and the RNA-seq example.

    The function we will use to map from Ensembl gene IDs to Entrez gene IDs is called mapIds().

    Let’s create a data frame that shows the mapped Entrez IDs along with the gene expression values for the respective Ensembl IDs.

    -
    # First let's create a mapped data frame we can join to the gene expression values
    -mapped_df <- data.frame(
    -  "entrez_id" = mapIds(
    -    org.Hs.eg.db, # Replace with annotation package for the organism relevant to your data
    -    keys = expression_df$Gene,
    -    column = "ENTREZID", # Replace with the type of gene identifiers you would like to map to
    -    keytype = "ENSEMBL", # Replace with the type of gene identifiers in your data
    -    multiVals = "first" # This will keep only the first mapped value for each Ensembl ID
    -  )
    -) %>%
    -  # If an Ensembl gene identifier doesn't map to a Entrez gene identifier, drop that
    -  # from the data frame
    -  dplyr::filter(!is.na(entrez_id)) %>%
    -  # Make an `Ensembl` column to store the row names
    -  tibble::rownames_to_column("Ensembl") %>%
    -  # Now let's join the rest of the expression data
    -  dplyr::inner_join(expression_df, by = c("Ensembl" = "Gene")) %>%
    -  # We won't be using Ensembl IDs moving forward, so we will drop this column
    -  dplyr::select(-Ensembl)
    +
    # First let's create a mapped data frame we can join to the gene expression values
    +mapped_df <- data.frame(
    +  "entrez_id" = mapIds(
    +    org.Hs.eg.db, # Replace with annotation package for the organism relevant to your data
    +    keys = expression_df$Gene,
    +    column = "ENTREZID", # Replace with the type of gene identifiers you would like to map to
    +    keytype = "ENSEMBL", # Replace with the type of gene identifiers in your data
    +    multiVals = "first" # This will keep only the first mapped value for each Ensembl ID
    +  )
    +) %>%
    +  # If an Ensembl gene identifier doesn't map to a Entrez gene identifier, drop that
    +  # from the data frame
    +  dplyr::filter(!is.na(entrez_id)) %>%
    +  # Make an `Ensembl` column to store the row names
    +  tibble::rownames_to_column("Ensembl") %>%
    +  # Now let's join the rest of the expression data
    +  dplyr::inner_join(expression_df, by = c("Ensembl" = "Gene"))
    ## 'select()' returned 1:many mapping between keys and columns

    This 1:many mapping between keys and columns message means that some Ensembl gene identifiers map to multiple Entrez IDs. In this case, it’s also possible that a Entrez ID will map to multiple Ensembl IDs. For the purpose of performing GSVA later in this notebook, we keep only the first mapped IDs. For more about how to explore this, take a look at our microarray gene ID conversion example.

    Let’s see a preview of mapped_df.

    -
    head(mapped_df)
    +
    head(mapped_df)

    We will want to keep in mind that GSVA requires that data is in a matrix with the gene identifiers as row names. In order to successfully turn our data frame into a matrix, we will need to ensure that we do not have any duplicate gene identifiers.

    Let’s check to see if we have any Entrez IDs that mapped to multiple Ensembl IDs.

    -
    any(duplicated(mapped_df$entrez_id))
    +
    any(duplicated(mapped_df$entrez_id))
    ## [1] TRUE

    Looks like we do have duplicated Entrez IDs. Let’s find out which Entrez IDs have been duplicated.

    -
    dup_entrez_ids <- mapped_df %>%
    -  dplyr::filter(duplicated(entrez_id)) %>%
    -  dplyr::pull(entrez_id)
    -
    -dup_entrez_ids
    -
    ## [1] "6013"   "148753"
    +
    dup_entrez_ids <- mapped_df %>%
    +  dplyr::filter(duplicated(entrez_id)) %>%
    +  dplyr::pull(entrez_id)
    +
    +dup_entrez_ids
    +
    ## [1] "6013" "3117"

    4.2.2.1 Handling duplicate gene identifiers

    As we mentioned earlier, we will not want any duplicate gene identifiers in our data frame when we convert it into a matrix in preparation for the GSVA steps later. GSVA is executed on a per sample basis so let’s keep the maximum expression value per sample associated with the duplicate Entrez gene identifiers. In other words, we will keep only the maximum expression value found across the duplicate Entrez gene identifier instances for each sample or column in this case.

    Let’s take a look at the rows associated with the duplicated Entrez IDs and see how this will play out.

    -
    mapped_df %>%
    -  dplyr::filter(entrez_id %in% dup_entrez_ids)
    +
    mapped_df %>%
    +  dplyr::filter(entrez_id %in% dup_entrez_ids)
    -

    As an example using the strategy we described, for GSM187153’s data in the first column, -0.007355525 is larger than -0.136553967 so moving forward, Entrez gene 6013 will have -0.007355525 value and the -0.136553967 would be dropped from the dataset.

    -

    However, this is just one method of handling duplicate gene identifiers. See the Gene Set Enrichment Analysis (GSEA) User guide for more information on other expression values that can be used, like the median expression value for example (Broad Institute Team 2019).

    -

    Now, let’s implement our choose the max value method for all samples and Entrez IDs using tidyverse functions.

    -
    max_dup_df <- mapped_df %>%
    -  # Filter to include only the rows associated with the duplicate Entrez gene identifiers
    -  dplyr::filter(entrez_id %in% dup_entrez_ids) %>%
    -  # Group by Entrez IDs
    -  dplyr::group_by(entrez_id) %>%
    -  # Get the maximum expression value using all values associated with each duplicate
    -  # Entrez ID for each column or sample in this case
    -  dplyr::summarize_all(max)
    -
    -max_dup_df
    +

    As an example using the strategy we described, for GSM917111’s data in the first column, 0.2294387 is larger than 0.1104345 so moving forward, Entrez gene 6013 will have 0.2294387 value and the 0.1104345 would be dropped from the dataset. However, this is just one method of handling duplicate gene identifiers. See the Gene Set Enrichment Analysis (GSEA) User guide for more information on other expression values that can be used, like the median expression value for example (Broad Institute Team 2019). Now, let’s implement our choose the max value method for all samples and Entrez IDs using tidyverse functions.

    +
    max_dup_df <- mapped_df %>%
    +  # We won't be using Ensembl IDs moving forward, so we will drop this column
    +  dplyr::select(-Ensembl) %>%
    +  # Filter to include only the rows associated with the duplicate Entrez gene identifiers
    +  dplyr::filter(entrez_id %in% dup_entrez_ids) %>%
    +  # Group by Entrez IDs
    +  dplyr::group_by(entrez_id) %>%
    +  # Get the maximum expression value using all values associated with each duplicate
    +  # Entrez ID for each column or sample in this case
    +  dplyr::summarize_all(max)
    +
    +max_dup_df
    -

    We can see GSM187153 now has the -0.007355525 value for Entrez ID 6013 like expected.

    -

    Looks like we were able to successfully get rid of the duplicate Entrez gene identifiers!

    +

    We can see GSM917111 now has the 0.2294387 value for Entrez ID 6013 like expected. Looks like we were able to successfully get rid of the duplicate Entrez gene identifiers!

    Now let’s combine our de-duplicated data with the rest of the mapped data!

    -
    filtered_mapped_df <- mapped_df %>%
    -  # First let's get the data associated with the Entrez gene identifiers that aren't duplicated
    -  dplyr::filter(!entrez_id %in% dup_entrez_ids) %>%
    -  # Now let's bind the rows of the maximum expression data we stored in `max_dup_df`
    -  dplyr::bind_rows(max_dup_df)
    +
    filtered_mapped_df <- mapped_df %>%
    +  # We won't be using Ensembl IDs moving forward, so we will drop this column
    +  dplyr::select(-Ensembl) %>%
    +  # First let's get the data associated with the Entrez gene identifiers that aren't duplicated
    +  dplyr::filter(!entrez_id %in% dup_entrez_ids) %>%
    +  # Now let's bind the rows of the maximum expression data we stored in `max_dup_df`
    +  dplyr::bind_rows(max_dup_df)

    As mentioned earlier, we need a matrix for GSVA. Let’s now convert our data frame into a matrix and prepare our object for GSVA.

    -
    filtered_mapped_matrix <- filtered_mapped_df %>%
    -  # We need to store our gene identifiers as row names
    -  tibble::column_to_rownames("entrez_id") %>%
    -  # Now we can convert our object into a matrix
    -  as.matrix()
    +
    filtered_mapped_matrix <- filtered_mapped_df %>%
    +  # We need to store our gene identifiers as row names
    +  tibble::column_to_rownames("entrez_id") %>%
    +  # Now we can convert our object into a matrix
    +  as.matrix()

    Note that if we had duplicate gene identifiers here, we would not be able to set them as row names.

    4.3 GSVA - Microarray

    -

    Addressed in upcoming PR

    +

    Rather than ranking genes based on some gene-level statistic selected by the user, GSVA fits a model and ranks genes based on their expression level relative to the sample distribution. The pathway-level score calculated is a way of asking how genes within a gene set vary as compared to genes that are outside of that gene set (Malhotra 2018).

    +

    The idea here is that we will get pathway-level scores for each sample that indicate if genes in a pathway vary concordantly in one direction (over-expressed or under-expressed relative to the overall population) (Hänzelmann et al. 2013a).

    +

    The output is a gene set by sample matrix of GSVA scores.

    +
    +

    4.3.1 Perform GSVA

    +

    Let’s perform GSVA using the gsva() function. See ?gsva for more options.

    +
    gsva_results <- gsva(
    +  filtered_mapped_matrix,
    +  hallmarks_list,
    +  method = "gsva",
    +  # Appropriate for our log2-transformed microarray data
    +  kcdf = "Gaussian",
    +  # Minimum gene set size
    +  min.sz = 15,
    +  # Maximum gene set size
    +  max.sz = 500,
    +  # Compute Gaussian-distributed scores
    +  mx.diff = TRUE,
    +  # Don't print out the progress bar
    +  verbose = FALSE
    +)
    +

    Let’s explore what the output of gsva() looks like.

    +
    head(gsva_results[, 1:10])
    +
    ##                                      GSM917111   GSM917250   GSM917281
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    -0.2784726 -0.29221444 -0.30693127
    +## HALLMARK_HYPOXIA                    -0.1907117 -0.13033725 -0.24058274
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    -0.2307863 -0.22997233 -0.25341066
    +## HALLMARK_MITOTIC_SPINDLE            -0.2134439  0.09773602 -0.13886393
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING -0.3061668  0.27041084 -0.06319446
    +## HALLMARK_TGF_BETA_SIGNALING         -0.2285640  0.08510027 -0.14161796
    +##                                      GSM917062   GSM917288   GSM917230
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    -0.2953894 -0.22966329 -0.20914620
    +## HALLMARK_HYPOXIA                    -0.2658532  0.06741065 -0.02691280
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    -0.2214914 -0.08702648 -0.03084332
    +## HALLMARK_MITOTIC_SPINDLE            -0.2020978 -0.17902098  0.05763884
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING -0.2363895  0.21274606  0.08273239
    +## HALLMARK_TGF_BETA_SIGNALING         -0.2284998  0.01208862 -0.13097578
    +##                                      GSM917152    GSM917242  GSM917226
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    0.33276903  0.001857506 -0.1329156
    +## HALLMARK_HYPOXIA                    0.18446386 -0.118269791 -0.2641157
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    0.05273271  0.104042284 -0.2136088
    +## HALLMARK_MITOTIC_SPINDLE            0.14226250 -0.052122165 -0.3753805
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING 0.37981263 -0.037661623 -0.3570903
    +## HALLMARK_TGF_BETA_SIGNALING         0.15915374  0.300603909 -0.1973818
    +##                                        GSM917290
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    -0.385841741
    +## HALLMARK_HYPOXIA                    -0.145480093
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    -0.267519873
    +## HALLMARK_MITOTIC_SPINDLE            -0.001471942
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING -0.006265662
    +## HALLMARK_TGF_BETA_SIGNALING         -0.130123427
    +
    +
    +
    +

    4.4 Find differentially expressed pathways

    +

    If we want to identify most differentially expressed pathways across subgroups, we can use functionality in the limma package to test the GSVA scores. This is one approach for working with GSVA scores. The mx.diff = TRUE argument that we supplied to the gsva() function in the previous section means the GSVA output scores should be normally distributed, which allows downstream analyses that make this assumption about the distribution (Hanzelmann et al. 2020).

    +
    +

    4.4.1 Create the design matrix

    +

    limma needs a numeric design matrix to signify which samples are of which subtype of medulloblastoma. Now we will create a model matrix based on our subgroup variable. We are using a + 0 in the model which sets the intercept to 0 so the subgroup effects capture expression for that group, rather than difference from the first group. If you have a control group, you might want that to be the intercept.

    +
    # Create the design matrix
    +des_mat <- model.matrix(~ metadata$subgroup + 0)
    +

    Let’s take a look at the design matrix we created.

    +
    # Print out the design matrix
    +head(des_mat)
    +
    ##   metadata$subgroupGroup 3 metadata$subgroupGroup 4 metadata$subgroupSHH
    +## 1                        0                        1                    0
    +## 2                        0                        1                    0
    +## 3                        0                        1                    0
    +## 4                        1                        0                    0
    +## 5                        0                        1                    0
    +## 6                        0                        1                    0
    +

    The design matrix column names are a bit messy, so we will neaten them up by dropping the metadata$subgroup designation they all have and for being able to reference them easily later, we want to drop spaces as well.

    +
    # Make the column names less messy
    +colnames(des_mat) <- stringr::str_remove(colnames(des_mat), "metadata\\$subgroup")
    +
    +# Do a similar thing but remove spaces in names
    +colnames(des_mat) <- stringr::str_remove(colnames(des_mat), " ")
    +

    Side note: If you are wondering why there are two \ above in "filtered_metadata\\$subgroup", that’s called an escape character. There’s a whole universe of things called regular expressions (regex) that can be super handy for string manipulations.

    +
    +
    +
    +

    4.5 Perform differential expression on pathway scores

    +

    Run the linear model on each pathway (each row of gsva_results).

    +
    # Apply linear model to data
    +fit <- limma::lmFit(gsva_results, design = des_mat)
    +
    +# Apply empirical Bayes to smooth standard errors
    +fit <- limma::eBayes(fit)
    +

    Now that we have our basic model fitting, we will want to make the contrasts among all our groups. Depending on your scientific questions, you will need to customize the next steps. Consulting the limma users guide for how to set up your model based on your hypothesis is a good idea.

    +

    In this contrasts matrix, we are comparing each subgroup to the average of the other subgroups.
    +We’re dividing by two in this expression so that each group is compared to the average of the other two groups (makeContrasts() doesn’t allow you to use functions like mean(); it wants a formula).

    +
    contrast_matrix <- makeContrasts(
    +  "G3vsOther" = Group3 - (Group4 + SHH) / 2,
    +  "G4vsOther" = Group4 - (Group3 + SHH) / 2,
    +  "SHHvsOther" = SHH - (Group3 + Group4) / 2,
    +  levels = des_mat
    +)
    +

    Side note: If you did have a control group you wanted to compare each group to, you could make each contrast to that control group, so the formulate would look like Group3 = Group3 - Control for each one. We highly recommend consulting the limma users guide for figuring out what your makeContrasts() and model.matrix() setups should look like (Ritchie et al. 2015).

    +

    Now that we have the contrasts matrix set up, we can use it to re-fit the model and re-smooth it with eBayes().

    +
    # Fit the model according to the contrasts matrix
    +contrasts_fit <- contrasts.fit(fit, contrast_matrix)
    +
    +# Re-smooth the Bayes
    +contrasts_fit <- eBayes(contrasts_fit)
    +

    Here’s a nifty article and example about what the empirical Bayes smoothing is for (Robinson).

    +

    Now let’s create the results table based on the contrasts fitted model.

    +

    This step will provide the Benjamini-Hochberg multiple testing correction. The topTable() function default is to use Benjamini-Hochberg but this can be changed to a different method using the adjust.method argument (see the ?topTable help page for more about the options).

    +
    # Apply multiple testing correction and obtain stats
    +stats_df <- topTable(contrasts_fit, number = nrow(expression_df)) %>%
    +  tibble::rownames_to_column("Gene")
    +

    Let’s take a peek at our results table.

    +
    head(stats_df)
    +
    + +
    +

    For each gene, each group’s fold change in expression, compared to the average of the other groups is reported.

    +

    By default, results are ordered from largest F value to the smallest, which means your most differentially expressed genes across all groups should be toward the top.

    +

    This means HALLMARK_UNFOLDED_PROTEIN_RESPONSE appears to be the pathway that contains the most significant distribution of scores across subgroups.

    +
    +
    +

    4.6 Visualizing Results

    +

    Let’s make a plot for our most significant pathway, HALLMARK_UNFOLDED_PROTEIN_RESPONSE.

    +
    +

    4.6.1 Sina plot

    +

    First we need to get our GSVA scores for this pathway into a long data frame, an appropriate format for ggplot2.

    +

    Let’s look at the current format of gsva_results.

    +
    head(gsva_results[, 1:10])
    +
    ##                                      GSM917111   GSM917250   GSM917281
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    -0.2784726 -0.29221444 -0.30693127
    +## HALLMARK_HYPOXIA                    -0.1907117 -0.13033725 -0.24058274
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    -0.2307863 -0.22997233 -0.25341066
    +## HALLMARK_MITOTIC_SPINDLE            -0.2134439  0.09773602 -0.13886393
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING -0.3061668  0.27041084 -0.06319446
    +## HALLMARK_TGF_BETA_SIGNALING         -0.2285640  0.08510027 -0.14161796
    +##                                      GSM917062   GSM917288   GSM917230
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    -0.2953894 -0.22966329 -0.20914620
    +## HALLMARK_HYPOXIA                    -0.2658532  0.06741065 -0.02691280
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    -0.2214914 -0.08702648 -0.03084332
    +## HALLMARK_MITOTIC_SPINDLE            -0.2020978 -0.17902098  0.05763884
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING -0.2363895  0.21274606  0.08273239
    +## HALLMARK_TGF_BETA_SIGNALING         -0.2284998  0.01208862 -0.13097578
    +##                                      GSM917152    GSM917242  GSM917226
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    0.33276903  0.001857506 -0.1329156
    +## HALLMARK_HYPOXIA                    0.18446386 -0.118269791 -0.2641157
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    0.05273271  0.104042284 -0.2136088
    +## HALLMARK_MITOTIC_SPINDLE            0.14226250 -0.052122165 -0.3753805
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING 0.37981263 -0.037661623 -0.3570903
    +## HALLMARK_TGF_BETA_SIGNALING         0.15915374  0.300603909 -0.1973818
    +##                                        GSM917290
    +## HALLMARK_TNFA_SIGNALING_VIA_NFKB    -0.385841741
    +## HALLMARK_HYPOXIA                    -0.145480093
    +## HALLMARK_CHOLESTEROL_HOMEOSTASIS    -0.267519873
    +## HALLMARK_MITOTIC_SPINDLE            -0.001471942
    +## HALLMARK_WNT_BETA_CATENIN_SIGNALING -0.006265662
    +## HALLMARK_TGF_BETA_SIGNALING         -0.130123427
    +

    We can see that they are in a wide format with the gsva scores for each sample spread across a row associated with each pathway.

    +

    Now let’s convert these results into a data frame and into a long format, using the tidyr::pivot_longer() function.

    +
    annotated_results_df <- gsva_results %>%
    +  # Make this into a data frame
    +  data.frame() %>%
    +  # Gene set names are row names
    +  tibble::rownames_to_column("pathway") %>%
    +  # Get into long format using the `tidyr::pivot_longer()` function
    +  tidyr::pivot_longer(
    +    cols = -pathway,
    +    names_to = "sample",
    +    values_to = "gsva_score"
    +  )
    +
    +# Preview the annotated results object
    +head(annotated_results_df)
    +
    + +
    +

    Now let’s filter to include only the scores associated with our most significant pathway, HALLMARK_UNFOLDED_PROTEIN_RESPONSE, and join the relevant group labels from the metadata for plotting.

    +
    top_pathway_annotated_results_df <- annotated_results_df %>%
    +  # Filter for only scores associated with our most significant pathway
    +  dplyr::filter(pathway == "HALLMARK_UNFOLDED_PROTEIN_RESPONSE") %>%
    +  # Join the column with the group labels that we would like to plot and compare --
    +  # Select the variables relevant to your data
    +  dplyr::left_join(metadata %>% dplyr::select(
    +    refinebio_accession_code,
    +    subgroup
    +  ),
    +  # Tell the join what columns are equivalent and should be used as a key
    +  by = c("sample" = "refinebio_accession_code")
    +  )
    +
    +# Preview the filtered annotated results object
    +head(top_pathway_annotated_results_df)
    +
    + +
    +

    Now let’s make a sina plot so we can look at the differences between the subgroup groups using our GSVA scores.

    +
    # Sina plot comparing GSVA scores for `HALLMARK_UNFOLDED_PROTEIN_RESPONSE` the `subgroup` groups in our dataset
    +sina_plot <-
    +  ggplot(
    +    top_pathway_annotated_results_df, # Supply our annotated data frame
    +    aes(
    +      x = subgroup, # Replace with a grouping variable relevant to your data
    +      y = gsva_score, # Column we created to store the GSVA scores in the last chunk
    +      color = subgroup # Let's make the groups different colors too
    +    )
    +  ) +
    +  # Add a boxplot that will have summary stats
    +  geom_boxplot(outlier.shape = NA) +
    +  # Make a sina plot that shows individual values
    +  ggforce::geom_sina() +
    +  # Rename the y-axis label
    +  labs(y = "HALLMARK_UNFOLDED_PROTEIN_RESPONSE_score") +
    +  # Adjust the plot background for better visualization
    +  theme_bw()
    +
    +# Display plot
    +sina_plot
    +

    +

    Looks like the Group 4 samples have lower GSVA scores for HALLMARK_UNFOLDED_PROTEIN_RESPONSE as compared to the SHH and Group 3 scores.

    +

    Let’s save this plot to PNG.

    +
    ggsave(file.path(plots_dir, "GSE37382_gsva_HALLMARK_UNFOLDED_PROTEIN_RESPONSE_sina_plot.png"),
    +  plot = sina_plot
    +)
    +
    ## Saving 7 x 5 in image
    +
    +
    +
    +

    4.7 Write results to file

    +

    Now let’s write all of our GSVA results to file.

    +
    gsva_results %>%
    +  as.data.frame() %>%
    +  tibble::rownames_to_column("pathway") %>%
    +  readr::write_tsv(file.path(
    +    results_dir,
    +    "GSE37382_gsva_results.tsv"
    +  ))

    5 Resources for further learning

    -

    Addressed in upcoming PR

    +

    6 Session info

    At the end of every analysis, before saving your notebook, we recommend printing out your session info. This helps make your code more reproducible by recording what versions of software and packages you used to run this.

    -
    # Print session info
    -sessioninfo::session_info()
    +
    # Print session info
    +sessioninfo::session_info()
    ## ─ Session info ───────────────────────────────────────────────────────────────
     ##  setting  value                       
     ##  version  R version 4.0.2 (2020-06-22)
    @@ -4256,7 +4506,7 @@ 

    6 Session info

    ## collate en_US.UTF-8 ## ctype en_US.UTF-8 ## tz Etc/UTC -## date 2020-11-20 +## date 2020-11-30 ## ## ─ Packages ─────────────────────────────────────────────────────────────────── ## package * version date lib source @@ -4273,6 +4523,7 @@

    6 Session info

    ## blob 1.2.1 2020-01-20 [1] RSPM (R 4.0.0) ## cli 2.1.0 2020-10-12 [1] RSPM (R 4.0.2) ## coda 0.19-4 2020-09-30 [1] RSPM (R 4.0.2) +## colorspace 1.4-1 2019-03-18 [1] RSPM (R 4.0.0) ## crayon 1.3.4 2017-09-16 [1] RSPM (R 4.0.0) ## DBI 1.1.0 2019-12-15 [1] RSPM (R 4.0.0) ## DelayedArray 0.16.0 2020-10-27 [1] Bioconductor @@ -4283,36 +4534,45 @@

    6 Session info

    ## estimability 1.3 2018-02-11 [1] RSPM (R 4.0.0) ## evaluate 0.14 2019-05-28 [1] RSPM (R 4.0.0) ## fansi 0.4.1 2020-01-08 [1] RSPM (R 4.0.0) +## farver 2.0.3 2020-01-16 [1] RSPM (R 4.0.0) +## fastmatch 1.1-0 2017-01-28 [1] RSPM (R 4.0.0) ## fftw 1.0-6 2020-02-24 [1] RSPM (R 4.0.2) ## generics 0.0.2 2018-11-29 [1] RSPM (R 4.0.0) ## GenomeInfoDb 1.26.0 2020-10-27 [1] Bioconductor ## GenomeInfoDbData 1.2.4 2020-11-18 [1] Bioconductor ## GenomicRanges 1.42.0 2020-10-27 [1] Bioconductor ## getopt 1.20.3 2019-03-22 [1] RSPM (R 4.0.0) +## ggforce 0.3.2 2020-06-23 [1] RSPM (R 4.0.2) +## ggplot2 * 3.3.2 2020-06-19 [1] RSPM (R 4.0.1) ## glue 1.4.2 2020-08-27 [1] RSPM (R 4.0.2) ## graph 1.68.0 2020-10-27 [1] Bioconductor ## GSEABase 1.52.0 2020-10-27 [1] Bioconductor ## GSVA * 1.38.0 2020-10-27 [1] Bioconductor +## gtable 0.3.0 2019-03-25 [1] RSPM (R 4.0.0) ## hms 0.5.3 2020-01-08 [1] RSPM (R 4.0.0) ## htmltools 0.5.0 2020-06-16 [1] RSPM (R 4.0.1) ## httr 1.4.2 2020-07-20 [1] RSPM (R 4.0.2) ## IRanges * 2.24.0 2020-10-27 [1] Bioconductor ## jsonlite 1.7.1 2020-09-07 [1] RSPM (R 4.0.2) ## knitr 1.30 2020-09-22 [1] RSPM (R 4.0.2) +## labeling 0.3 2014-08-23 [1] RSPM (R 4.0.0) ## lattice 0.20-41 2020-04-02 [2] CRAN (R 4.0.2) ## lifecycle 0.2.0 2020-03-06 [1] RSPM (R 4.0.0) ## limma * 3.46.0 2020-10-27 [1] Bioconductor ## magrittr * 1.5 2014-11-22 [1] RSPM (R 4.0.0) +## MASS 7.3-51.6 2020-04-26 [2] CRAN (R 4.0.2) ## Matrix 1.2-18 2019-11-27 [2] CRAN (R 4.0.2) ## MatrixGenerics 1.2.0 2020-10-27 [1] Bioconductor ## matrixStats 0.57.0 2020-09-25 [1] RSPM (R 4.0.2) ## memoise 1.1.0 2017-04-21 [1] RSPM (R 4.0.0) +## munsell 0.5.0 2018-06-12 [1] RSPM (R 4.0.0) ## mvtnorm 1.1-1 2020-06-09 [1] RSPM (R 4.0.0) ## nlme 3.1-148 2020-05-24 [2] CRAN (R 4.0.2) ## optparse * 1.6.6 2020-04-16 [1] RSPM (R 4.0.0) ## org.Hs.eg.db * 3.12.0 2020-11-18 [1] Bioconductor ## pillar 1.4.6 2020-07-10 [1] RSPM (R 4.0.2) ## pkgconfig 2.0.3 2019-09-22 [1] RSPM (R 4.0.0) +## polyclip 1.10-0 2019-03-14 [1] RSPM (R 4.0.0) ## ps 1.4.0 2020-10-07 [1] RSPM (R 4.0.2) ## purrr 0.3.4 2020-04-17 [1] RSPM (R 4.0.0) ## qusage * 2.24.0 2020-10-27 [1] Bioconductor @@ -4330,13 +4590,16 @@

    6 Session info

    ## RSQLite 2.2.1 2020-09-30 [1] RSPM (R 4.0.2) ## rstudioapi 0.11 2020-02-07 [1] RSPM (R 4.0.0) ## S4Vectors * 0.28.0 2020-10-27 [1] Bioconductor +## scales 1.1.1 2020-05-11 [1] RSPM (R 4.0.0) ## sessioninfo 1.1.1 2018-11-05 [1] RSPM (R 4.0.0) ## stringi 1.5.3 2020-09-09 [1] RSPM (R 4.0.2) ## stringr 1.4.0 2019-02-10 [1] RSPM (R 4.0.0) ## styler 1.3.2 2020-02-23 [1] RSPM (R 4.0.0) ## SummarizedExperiment 1.20.0 2020-10-27 [1] Bioconductor ## tibble 3.0.4 2020-10-12 [1] RSPM (R 4.0.2) +## tidyr 1.1.2 2020-08-27 [1] RSPM (R 4.0.2) ## tidyselect 1.1.0 2020-05-11 [1] RSPM (R 4.0.0) +## tweenr 1.0.1 2018-12-14 [1] RSPM (R 4.0.2) ## vctrs 0.3.4 2020-08-29 [1] RSPM (R 4.0.2) ## withr 2.3.0 2020-09-22 [1] RSPM (R 4.0.2) ## xfun 0.18 2020-09-29 [1] RSPM (R 4.0.2) @@ -4361,14 +4624,29 @@

    References

    Dolgalev I., 2020 Msigdbr: MSigDB gene sets for multiple organisms in a tidy data format. https://cran.r-project.org/web/packages/msigdbr/index.html

    +
    +

    Hanzelmann S., R. Castelo, and J. Guinney, 2020 GSVA: The gene set variation analysis package for microarray and rna-seq data. https://www.bioconductor.org/packages/release/bioc/vignettes/GSVA/inst/doc/GSVA.pdf

    +

    Hänzelmann S., R. Castelo, and J. Guinney, 2013a Biases in Illumina transcriptome sequencing caused by random hexamer priming. BMC Bioinformatics 14. https://doi.org/10.1186/1471-2105-14-7

    Hänzelmann S., R. Castelo, and J. Guinney, 2013b GSVA. https://github.com/rcastelo/GSVA/blob/master/man/gsva.Rd

    -
    -

    Meng H., G. Yaari, C. R. Bolen, S. Avey, and S. H. Kleinstein, 2019 Gene set meta-analysis with quantitative set analysis for gene expression (qusage). PLoS Computat Biol. 15: e1006899. https://doi.org/10.1371/journal.pcbi.1006899

    +
    +

    Malhotra S., 2018 Decoding gene set variation analysis. https://towardsdatascience.com/decoding-gene-set-variation-analysis-8193a0cfda3

    +
    +
    +

    Northcott P., D. Shih, J. Peacock, L. Garzia, and S. Morrissy et al., 2012 Subgroup specific structural variation across 1,000 medulloblastoma genomes. Nature 488. https://doi.org/10.1038/nature11327

    +
    +
    +

    Ritchie M. E., B. Phipson, D. Wu, Y. Hu, and C. W. Law et al., 2015 limma powers differential expression analyses for RNA-sequencing and microarray studies. Nucleic Acids Research 43: e47. https://doi.org/10.1093/nar/gkv007

    +
    +
    +

    Robinson D., Understanding empirical Bayes estimation (using baseball statistics). http://varianceexplained.org/r/empirical_bayes_baseball/

    +
    +
    +

    Yaari G., C. R. Bolen, J. Thakar, and S. H. Kleinstein, 2013 Quantitative set analysis for gene expression: A method to quantify gene set differential expression including gene-gene correlations. Nucleic Acids Research 41: e170. https://doi.org/10.1093/nar/gkt660

    diff --git a/components/dictionary.txt b/components/dictionary.txt index ae78912d..8fe5cca5 100644 --- a/components/dictionary.txt +++ b/components/dictionary.txt @@ -28,6 +28,7 @@ ColorBrewer Compara ComplexHeatmap ComplexHeatmap's +concordantly CREB Crouser cytosolic diff --git a/components/references.bib b/components/references.bib index ddede529..d5e90dca 100644 --- a/components/references.bib +++ b/components/references.bib @@ -291,6 +291,13 @@ @website{Hanzelmann-github url = {https://github.com/rcastelo/GSVA/blob/master/man/gsva.Rd} } +@manual{Hanzelmann-gsva-vignette, + title = {GSVA: The Gene Set Variation Analysis package for microarray and RNA-seq data}, + author = {Sonja Hanzelmann and Robert Castelo and Justin Guinney}, + year = {2020}, + url = {https://www.bioconductor.org/packages/release/bioc/vignettes/GSVA/inst/doc/GSVA.pdf}, +} + @manual{Hastie2020, title = {impute: Imputation for microarray data}, author = {Trevor Hastie and Robert Tibshirani and Balasubramanian Narasimhan and Gilbert Chu}, From 55ed7581d249e83f8ffc5e56fe8e337f1b1f4f5f Mon Sep 17 00:00:00 2001 From: Candace Savonen Date: Tue, 1 Dec 2020 08:05:11 -0500 Subject: [PATCH 50/50] Remove zip file that we don't need published --- 01-getting-started/getting-started.html.zip | Bin 309220 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 01-getting-started/getting-started.html.zip diff --git a/01-getting-started/getting-started.html.zip b/01-getting-started/getting-started.html.zip deleted file mode 100644 index 706b0db8808bdd56a17e9e79d2fd44ca92c42460..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 309220 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 !ay+RYGoE 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%0AS3JUM-bE^lcN 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ϖL(9N;ZuE%mvPNzh`DajOD-o@!MDi06>l~- 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

    EU;L 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