├── .Rbuildignore ├── .Rhistory ├── .gitattributes ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── MRPracticals.Rproj ├── MVMR.Rproj ├── NAMESPACE ├── R ├── BMIdat.R ├── egger_radial.R ├── format_function.R ├── format_radial.R ├── funnel_radial.R ├── ivw_mvmr.R ├── ivw_radial.R ├── mvmr.R ├── phenocov_mvmr.R ├── pleiotropy_mvmr.R ├── plot_radial.R ├── plotly_radial.R ├── rawdat_mvmr.R ├── snpcov_mvmr.R └── strength_mvmr.R ├── README.md ├── data ├── BMIdat.RData └── rawdat_mvmr.RData ├── man ├── BMIdat.Rd ├── egger_radial.Rd ├── format_mvmr.Rd ├── format_radial.Rd ├── funnel_radial.Rd ├── ivw_mvmr.Rd ├── ivw_radial.Rd ├── mvmr.Rd ├── phenocov_mvmr.Rd ├── pleiotropy_mvmr.Rd ├── plot_radial.Rd ├── plotly_radial.Rd ├── rawdat_mvmr.Rd ├── snpcov_mvmr.Rd └── strength_mvmr.Rd └── vignettes ├── .gitignore ├── BMIdat.csv ├── MRBase.Rmd ├── MRBase.html ├── MRBase_files └── figure-html │ ├── unnamed-chunk-28-1.png │ ├── unnamed-chunk-30-1.png │ ├── unnamed-chunk-31-1.png │ └── unnamed-chunk-32-1.png ├── MVMR Tutorial.html ├── MVMR Tutorial.rmd ├── RadialMR.Rmd ├── RadialMR.html ├── ao.csv ├── exG1.csv ├── exG2.csv └── png └── workflow.png /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^MVMR\.Rproj$ 2 | ^\.Rproj\.user$ 3 | -------------------------------------------------------------------------------- /.Rhistory: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/.Rhistory -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: MRPracticals 2 | Title: An R Package illustrating features of MR Base and RadialMR 3 | Version: 0.0.1 4 | Authors@R: c(person("Wes", "Spiller", email = "wes.spiller@bristol.ac.uk", role = c("aut", "cre")), person("Jack", "Bowden", email = "jack.bowden@bristol.ac.uk", role = c("aut"))) 5 | Description: This package is designed to present information and guidance for MR practical sessions, designed by the MRC Integrative Epidemiology Unit at the University of Bristol. 6 | Depends: R (>= 3.5.1) 7 | License: GPL(>= 2) 8 | Encoding: UTF-8 9 | LazyData: true 10 | Imports: knitr, rmarkdown, RadialMR, kableExtra, captioner, stringr, MRInstruments, TwoSampleMR, plotly 11 | Remotes: WSpiller/RadialMR, 12 | WSpiller/MVMR, 13 | MRCIEU/TwoSampleMR, 14 | MRCIEU/MRInstruments 15 | VignetteBuilder: knitr 16 | RoxygenNote: 7.1.0.9000 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /MRPracticals.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | Encoding: UTF-8 9 | 10 | AutoAppendNewline: Yes 11 | StripTrailingWhitespace: Yes 12 | 13 | BuildType: Package 14 | PackageUseDevtools: Yes 15 | PackageInstallArgs: --no-multiarch --with-keep.source 16 | PackageRoxygenize: rd,collate,namespace 17 | -------------------------------------------------------------------------------- /MVMR.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(egger_radial) 4 | export(format_mvmr) 5 | export(format_radial) 6 | export(funnel_radial) 7 | export(ivw_mvmr) 8 | export(ivw_radial) 9 | export(mvmr) 10 | export(phenocov_mvmr) 11 | export(pleiotropy_mvmr) 12 | export(plot_radial) 13 | export(plotly_radial) 14 | export(snpcov_mvmr) 15 | export(strength_mvmr) 16 | -------------------------------------------------------------------------------- /R/BMIdat.R: -------------------------------------------------------------------------------- 1 | #' Example Two-Sample Summary Data for use in MR Practicals. 2 | #' 3 | #' A dataset containing summary data for 62 independent SNPs associated with body mass index from Locke (2015), and summary estimates for their corresponding 4 | #' association with systolic blood pressure from the UK Biobank. 5 | #' 6 | #' BMIdat. 7 | #' 8 | #' @format A data frame with 62 rows and 43 variables, created using code presented in \code{vignette("MRBase")}. 9 | #' 10 | #' @source 11 | #' \itemize{ 12 | #' \item \url{https://www.nature.com/articles/nature14177} 13 | #' \item \url{http://www.nealelab.is/blog/2017/9/11/details-and-considerations-of-the-uk-biobank-gwas} 14 | #' } 15 | 16 | #'@author Wes Spiller; Jack Bowden 17 | 18 | "BMIdat" 19 | -------------------------------------------------------------------------------- /R/egger_radial.R: -------------------------------------------------------------------------------- 1 | #' egger_radial 2 | #' 3 | #' Fits a radial MR-Egger model using first order, second order, or modified second order weights. Outliers are identified using a significance threshold specified by the user. The function returns an object of class \code{"egger"}, containing regression estimates, a measure of total heterogeneity using Rucker's Q statistic, the individual contribution to overall heterogeneity of each variant, and a data frame for use in constructing the radial plot. 4 | #' 5 | #' @param r_input A formatted data frame using the \code{format_radial} function. 6 | #' @param alpha A value specifying the statistical significance threshold for identifying outliers (\code{0.05} specifies a p-value threshold of 0.05). 7 | #' @param weights A value specifying the inverse variance weights used to calculate the MR-Egger estimate and Rucker's Q statistic. By default modified second order weights are used, but one can choose to select first order (\code{1}), second order (\code{2}) or modified second order weights (\code{3}). 8 | #' @param summary Indicates whether a summary of the radial MR-Egger model should be printed (default= \code{TRUE}) or withheld (\code{FALSE}). 9 | #' @return An object of class \code{"egger"} containing the following components:\describe{ 10 | #' \item{\code{coef}}{A matrix giving the intercept and slope coefficient, corresponding standard errors, t-statistics, and (two-sided) p-values.} 11 | #' \item{\code{qstatistic}}{Rucker's Q statistic for overall heterogeneity.} 12 | #' \item{\code{df}}{Degrees of freedom. This is equal to the number of variants -2 when fitting the radial MR-Egger model.} 13 | #' \item{\code{outliers}}{A data frame containing variants identified as outliers, with respective Q statistics, chi-squared tests and SNP identification.} 14 | #' \item{\code{data}}{A data frame containing containing SNP IDs, inverse variance weights, the product of the inverse variance weight and ratio estimate for each variant, contribution to overall heterogeneity with corresponding p-value, and a factor indicator showing outlier status.} 15 | #' \item{\code{confint}}{A vector giving lower and upper confidence limits for the radial MR-Egger effect estimate.} 16 | #'} 17 | #'@author Wes Spiller; Jack Bowden. 18 | #'@references Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 19 | #'@export 20 | #'@examples 21 | #' 22 | #' egger_radial(r_input,0.05,1) 23 | #' 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | egger_radial<-function(r_input,alpha,weights,summary){ 42 | 43 | #Define ratio estimates 44 | Ratios<-r_input[,3]/r_input[,2] 45 | 46 | if(missing(alpha)) { 47 | alpha<-0.05 48 | warning("Significance threshold for outlier detection not specified: Adopting a 95% threshold") 49 | } 50 | 51 | if(missing(weights)) { 52 | weights<-3 53 | warning("Weights not specified: Adopting modified second-order weights") 54 | } 55 | 56 | if(missing(summary)) { 57 | summary<-TRUE 58 | } 59 | 60 | if(weights==1){ 61 | 62 | #Define inverse variance weights 63 | W<-((r_input[,2]^2)/(r_input[,5]^2)) 64 | 65 | } 66 | 67 | if(weights==2){ 68 | 69 | #Define inverse variance weights 70 | W<-((r_input[,5]^2/r_input[,2]^2)+((r_input[,3]^2*r_input[,4]^2)/r_input[,2]^4))^-1 71 | 72 | } 73 | 74 | if(weights==3){ 75 | 76 | #Define inverse variance weights 77 | W<-((r_input[,2]^2)/(r_input[,5]^2)) 78 | 79 | } 80 | 81 | #Define vector of squared weights 82 | Wj<-sqrt(W) 83 | 84 | #Define vector of weights * ratio estimates 85 | BetaWj<-Ratios*Wj 86 | 87 | #Define Egger Model 88 | Egger.Model<-lm(BetaWj~Wj) 89 | 90 | #Define output of Egger.Model fit 91 | EstimatesEGGER<-summary(Egger.Model) 92 | 93 | #Define intercept of Egger.Model 94 | Egger.Intercept<-EstimatesEGGER$coefficients[1] 95 | 96 | #Define slope of Egger.Model 97 | Egger.Slope<-EstimatesEGGER$coefficients[2] 98 | 99 | #Define standard error for intercept of Egger.Model 100 | Eggerintercept.SE<-EstimatesEGGER$coefficients[3] 101 | 102 | #Define standard error for slope of Egger.Model 103 | Eggerslope.SE<-EstimatesEGGER$coefficients[4] 104 | 105 | #Define 95% confidence interval for Egger.Model intercept 106 | Eggerint_CI<-as.numeric(confint(Egger.Model)[1,]) 107 | 108 | #Define 95% confidence interval for Egger.Model slope 109 | Eggerslope_CI<-as.numeric(confint(Egger.Model)[2,]) 110 | 111 | #Define Q statistic for each individual variant 112 | Qj<-W*(Ratios-(Egger.Intercept/Wj)-Egger.Slope)^2 113 | 114 | #Define total Q statistic 115 | Total_Q<-sum(Qj) 116 | 117 | #Perform chi square test for overall Q statistic 118 | Total_Q_chi<-pchisq(Total_Q,length(r_input[,2])-2,lower.tail = FALSE) 119 | 120 | 121 | 122 | if(weights==3){ 123 | #Define inverse variance weights 124 | W<- ((r_input[,5]^2+(Egger.Slope^2*r_input[,4]^2))/r_input[,2]^2)^-1 125 | 126 | #Define vector of squared weights 127 | Wj<-sqrt(W) 128 | 129 | #Define vector of weights * ratio estimates 130 | BetaWj<-Ratios*Wj 131 | 132 | #Define Egger Model 133 | Egger.Model<-lm(BetaWj~Wj) 134 | 135 | #Define output of Egger.Model fit 136 | EstimatesEGGER<-summary(Egger.Model) 137 | 138 | #Define intercept of Egger.Model 139 | Egger.Intercept<-EstimatesEGGER$coefficients[1] 140 | 141 | #Define slope of Egger.Model 142 | Egger.Slope<-EstimatesEGGER$coefficients[2] 143 | 144 | #Define standard error for intercept of Egger.Model 145 | Eggerintercept.SE<-EstimatesEGGER$coefficients[3] 146 | 147 | #Define standard error for slope of Egger.Model 148 | Eggerslope.SE<-EstimatesEGGER$coefficients[4] 149 | 150 | #Define 95% confidence interval for Egger.Model intercept 151 | Eggerint_CI<-as.numeric(confint(Egger.Model)[1,]) 152 | 153 | #Define 95% confidence interval for Egger.Model slope 154 | Eggerslope_CI<-as.numeric(confint(Egger.Model)[2,]) 155 | 156 | #Define Q statistic for each individual variant 157 | Qj<-W*(Ratios-(Egger.Intercept/Wj)-Egger.Slope)^2 158 | 159 | #Define total Q statistic 160 | Total_Q<-sum(Qj) 161 | 162 | #Perform chi square test for overall Q statistic 163 | Total_Q_chi<-pchisq(Total_Q,length(r_input[,2])-1,lower.tail = FALSE) 164 | 165 | } 166 | 167 | #Define a placeholder vector of 0 values for chi square tests 168 | Qj_Chi<-0 169 | 170 | #Perform chi square tests for each Qj value 171 | for(i in 1:length(Qj)){ 172 | Qj_Chi[i]<-pchisq(Qj[i],1,lower.tail = FALSE) 173 | } 174 | 175 | #Define dataframe with SNP IDs and outlier statistics 176 | r_input$Qj<-Qj 177 | r_input$Qj_Chi<-Qj_Chi 178 | 179 | #Define a placeholder vector of 0 values for identifying outliers 180 | Out_Indicator<-rep(0,length(r_input[,2])) 181 | 182 | #For loop defining outlier indicator variable. 183 | for( i in 1:length(r_input[,2])){ 184 | if(Qj_Chi[i]0)){ 203 | outlier_status<-"Outliers detected" 204 | 205 | #Generate a subset of data containing only outliers 206 | Out_Dat<-subset(r_input, Outliers == "Outlier") 207 | 208 | #Construct a datafrae containing SNP IDs, Q statistics and chi-square values for each outlying variant 209 | outtab<-data.frame(Out_Dat[,1],Out_Dat$Qj,Out_Dat$Qj_Chi) 210 | 211 | #Redefine column names 212 | colnames(outtab) = c("SNP","Q_statistic","p.value") 213 | 214 | } 215 | 216 | if(summary==TRUE){ 217 | 218 | # Print a few summary elements that are common to both lm and plm model summary objects 219 | cat("\n") 220 | 221 | cat("Radial MR-Egger\n") 222 | 223 | cat("\n") 224 | 225 | print(coef(EstimatesEGGER)) 226 | 227 | cat("\nResidual standard error:", round(EstimatesEGGER$sigma,3), "on", EstimatesEGGER$df[2], "degrees of freedom") 228 | 229 | cat("\n") 230 | 231 | cat(paste(c("\nF-statistic:", " on"," and"), round(EstimatesEGGER$fstatistic,2), collapse=""), 232 | "DF, p-value:", 233 | format.pval(pf(EstimatesEGGER$fstatistic[1L], EstimatesEGGER$fstatistic[2L], EstimatesEGGER$fstatistic[3L], 234 | lower.tail = FALSE), digits=3)) 235 | 236 | cat("\n") 237 | 238 | cat("Q-Statistic for heterogeneity:",Total_Q, "on", length(r_input[,2])-2, "DF",",", "p-value:" , Total_Q_chi) 239 | 240 | cat("\n") 241 | 242 | cat("\n",outlier_status,"\n") 243 | 244 | cat("\n") 245 | 246 | } 247 | 248 | out_data<-data.frame(r_input[,1],r_input[,6],r_input[,7],r_input[,8]) 249 | out_data$Wj<-Wj 250 | out_data$BetaWj<-BetaWj 251 | out_data<-out_data[c(1,5,6,2,3,4)] 252 | names(out_data)<-c("SNP","Wj","BetaWj","Qj","Qj_Chi","Outliers") 253 | 254 | multi_return <- function() { 255 | Out_list <- list("coef" = EstimatesEGGER$coef,"qstatistic"= Total_Q, "df" = length(r_input[,2])-1, "outliers" = outtab, "data" = out_data, "confint" = Eggerslope_CI) 256 | class(Out_list)<-"egger" 257 | 258 | return(Out_list) 259 | } 260 | OUT<-multi_return() 261 | 262 | } -------------------------------------------------------------------------------- /R/format_function.R: -------------------------------------------------------------------------------- 1 | #' format_mvmr 2 | #' 3 | #' Reads in summary data. Checks and organises columns for use in calculating multivariable Mendelian Randomization analyses. Where variant IDs are not provided, a vector is generated for variant identification. 4 | #' 5 | #' @param BXGs A matrix containing beta-coefficient values for genetic associations with the each exposure. Columns should indicate exposure number, with rows representing estimates for a given genetic variant. 6 | #' @param BYG A numeric vector of beta-coefficient values for genetic associations with the outcome. 7 | #' @param seBXGs A matrix containing standard errors corresponding to the matrix of beta-coefficients \code{BXGs}. 8 | #' @param seBYG A numeric vector of standard errors corresponding to the beta-coefficients \code{BYG}. 9 | #' @param RSID A vector of names for genetic variants included in the analysis. If variant IDs are not provided (\code{RSID="NULL"}), a vector of ID numbers will be generated. 10 | #' @return A formatted data frame. 11 | #' 12 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 13 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 14 | #'@export 15 | #'@examples 16 | #' 17 | #' format_mvmr(summarydata[,c(1,2)],summarydata[,5],summarydata[,c(3,4)],summarydata[,6]) 18 | #' 19 | 20 | #Function for formatting MVMR data frame 21 | 22 | #Define formating function: This takes as inputs a matrix of instrument-exposure 23 | #associations, a vector of instrument-outcome associations, a matrix of 24 | #corresponding instrument-exposure standard errors, and a vector of identification 25 | #numbers for the instruments. 26 | 27 | format_mvmr<-function(BXGs,BYG,seBXGs,seBYG,RSID){ 28 | 29 | #If no instrument-identification vector is provided, a set of placeholder values 30 | #is produced. A warning is also given to indicate no values were provided 31 | 32 | if(missing(RSID)) { 33 | RSID<-seq(from=1,to=length(BYG),by=1) 34 | warning("Missing SNP IDs; Generating placeholders") 35 | } 36 | 37 | #This loop names each column of instrument-exposure associations in the order 38 | #they appear in the provided matrix, labeling each exposure with an X and 39 | #subsequent index number. The first exposure provided is labelled betaX1. 40 | 41 | BXGs<-data.frame(BXGs) 42 | seBXGs<-data.frame(seBXGs) 43 | BYG<-data.frame(BYG) 44 | seBYG<-data.frame(seBYG) 45 | RSID<-data.frame(RSID) 46 | 47 | 48 | 49 | for(i in 1:ncol(BXGs)){ 50 | names(BXGs)[i]<-paste0("betaX",i,collapse=",") 51 | } 52 | 53 | #This loop names each column of instrument-exposure standard errors in the order 54 | #they appear in the provided matrix, labeling each exposure with an X and 55 | #subsequent index number. The standard error for the first exposure provided 56 | #is labelled sebetaX1. 57 | 58 | for(i in 1:ncol(seBXGs)){ 59 | names(seBXGs)[i]<-paste0("sebetaX",i,collapse=",") 60 | } 61 | 62 | # A dataframe containing all the necessary information for performing 63 | #multivariable MR is created, placing the variables in a specific order. 64 | 65 | dat<-cbind(RSID,BYG,seBYG,BXGs,seBXGs) 66 | 67 | # The columns of the dataframe are renamed so as to be interpretable in 68 | #subsequent functions. 69 | 70 | for(i in 1:ncol(dat)){ 71 | 72 | if(i>1){ 73 | dat[,i]<-as.numeric(dat[,i]) 74 | 75 | } 76 | 77 | } 78 | 79 | names(dat)<-c("SNP","betaYG","sebetaYG",names(BXGs),names(seBXGs)) 80 | 81 | # The function returns the formatted dataframe 82 | 83 | return(dat) 84 | } -------------------------------------------------------------------------------- /R/format_radial.R: -------------------------------------------------------------------------------- 1 | #' format_radial 2 | #' 3 | #' Reads in summary data. Checks and organises columns for use in calculating radial IVW and radial MR-Egger estimates. Where variant IDs are not provided, a vector is generated for variant identification. 4 | #' 5 | #' @param BXG A numeric vector of beta-coefficient values for genetic associations with the first variable (exposure). 6 | #' @param BYG A numeric vector of beta-coefficient values for genetic associations with the second variable (outcome). 7 | #' @param seBXG The standard errors corresponding to the beta-coefficients \code{BXG}. 8 | #' @param seBYG The standard errors corresponding to the beta-coefficients \code{BYG}. 9 | #' @param RSID A vector of names for genetic variants included in the analysis. If variant IDs are not provided (\code{RSID="NULL"}), a vector of ID numbers will be generated. 10 | #' @return A formatted data frame. 11 | #' 12 | #'@author Wes Spiller; Jack Bowden. 13 | #'@references Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 14 | #'@export 15 | #'@examples 16 | #' 17 | #' format_radial(summarydata[,1],summarydata[,3],summarydata[,2],summarydata[,4]) 18 | #' 19 | 20 | #Function for formatting data frame 21 | 22 | format_radial<-function(BXG,BYG,seBXG,seBYG,RSID){ 23 | 24 | #Generates placeholder SNP IDs if not provided. 25 | 26 | if(missing(RSID)) { 27 | RSID<-seq(from=1,to=length(BYG),by=1) 28 | 29 | warning("Missing SNP IDs; Generating placeholders") 30 | } 31 | 32 | #Rearrange variable order in formatted data frame 33 | F.Data<-data.frame(RSID,BXG,BYG,seBXG,seBYG) 34 | 35 | #Rename variables based on MRBase conventional names 36 | names(F.Data)<-c("SNP","beta.exposure","beta.outcome","se.exposure","se.outcome") 37 | 38 | return(F.Data) 39 | } 40 | -------------------------------------------------------------------------------- /R/funnel_radial.R: -------------------------------------------------------------------------------- 1 | #' funnel_radial 2 | #' 3 | #' A function for producing generalized radial IVW and MR-Egger funnel plots either individually or simultaneously. The function also allows for lines indicating the magnitude for the MR Egger transformation for each variant, though it should be noted that this distance is a function of the weight attributed to the variant, and is therefore not indicative of outliers. 4 | #' 5 | #' @param r_object An object of class \code{"IVW"} or \code{"egger"}. For visualising both estimates simultaneously, both objects should be included as a vector c(\code{A},\code{B}), where \code{A} and \code{B} denote the \code{"IVW"} and \code{"egger"} objects respectively. 6 | #' @param show_transform Indicates whether to produce a plot including lines showing the magnitude of the MR Egger transformation for each variant (\code{TRUE}), or a scatterplot showing only the variants and corresponding estimates (\code{FALSE}). 7 | #' @return A ggplot object containing a radial funnel plot of either the IVW, MR-Egger, or both estimates simultaneously. 8 | #'@author Wes Spiller; Jack Bowden. 9 | #'@references Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 10 | #'@export 11 | #'@examples 12 | #' 13 | #'funnel_radial(r_object,TRUE) 14 | 15 | funnel_radial<-function(r_object,show_transform){ 16 | 17 | if(missing(show_transform)) { 18 | show_transform<-FALSE 19 | } 20 | 21 | 22 | #Load ggplot2 library 23 | library(ggplot2) 24 | 25 | if(length(r_object)>=6 && length(r_object)<=13){ 26 | 27 | if(class(r_object)=="IVW"){ 28 | 29 | #Produce plot showing full scale and all variants 30 | B<-ggplot(r_object$data,aes(x=r_object$data$BetaWj/r_object$data$Wj,y=Wj))+labs(title="Radial Funnel Plot")+ geom_point(aes(colour="Variant"))+ 31 | theme_bw()+theme(panel.border = element_blank(),panel.grid.major = element_blank(),panel.grid.minor = element_blank(), 32 | axis.line = element_line(colour = "black"))+xlab(expression(hat(beta)[j]))+ylab(expression(sqrt(W[j])))+ 33 | geom_segment(aes(x = r_object$coef[1], xend = r_object$coef[1], y = 0, yend = max(r_object$data$Wj),colour="IVW Estimate"))+ 34 | geom_segment(aes(x = r_object$confint[1], xend = r_object$confint[2], y = 0, yend = 0,colour="IVW Estimate"))+ 35 | scale_y_continuous(limits = c(-0.2,max(r_object$data$Wj)))+ 36 | scale_color_manual(name="",breaks=c("Variant","IVW Estimate"),values=c("Variant"="black","IVW Estimate"="#56B4E9"))+ 37 | geom_text(x=r_object$coef[1], y=-0.2, 38 | label=paste(round(r_object$coef[1],digits=3),paste("(",round(r_object$confint[1],digits=2),",",round(r_object$confint[2],digits=2),")"),collapse=""),size=3) 39 | 40 | # geom_text(x=r_object$coef[1], y=-0.2, 41 | # label=round(r_object$coef[1],digits=3),size=3) 42 | } 43 | 44 | if(class(r_object)=="egger"){ 45 | 46 | transeg<-(r_object$data$BetaWj/r_object$data$Wj)-(r_object$coef[1,1]/r_object$data$Wj) 47 | Wj<-r_object$data$Wj 48 | temp<-data.frame(transeg,Wj) 49 | 50 | #Produce plot showing full scale and all variants 51 | B<-ggplot(temp,aes(x=transeg,y=Wj))+labs(title="Radial Funnel Plot")+ geom_point(aes(colour="Variant"))+ 52 | theme_bw()+theme(panel.border = element_blank(),panel.grid.major = element_blank(),panel.grid.minor = element_blank(), 53 | axis.line = element_line(colour = "black"))+xlab(expression(hat(beta)[j]))+ylab(expression(sqrt(W[j])))+ 54 | geom_segment(aes(x = r_object$coef[2,1], xend = r_object$coef[2,1], y = 0, yend = max(r_object$data$Wj),colour="MR Egger Estimate"))+ 55 | geom_segment(aes(x = r_object$confint[1], xend = r_object$confint[2], y = 0, yend = 0,colour="MR Egger Estimate"))+ 56 | scale_y_continuous(limits = c(-0.2,max(r_object$data$Wj)))+ 57 | scale_color_manual(name="",breaks=c("Variant","MR Egger Estimate"),values=c("Variant"="black","MR Egger Estimate"="#D55E00"))+ 58 | geom_text(x=r_object$coef[2,1], y=-0.2, 59 | label=paste(round(r_object$coef[2,1],digits=3),paste("(",round(r_object$confint[1],digits=2),",",round(r_object$confint[2],digits=2),")"),collapse=""),size=3) 60 | } 61 | 62 | } 63 | 64 | if(length(r_object)==19){ 65 | 66 | names(r_object)<-c("IVW.coef","IVW.qstatistic","IVW.df","IVW.outliers","data","IVW.confint","it.coef","Fex.coef", 67 | "Rex.coef","It.confint","Fex.confint","Rex.confint","meanF","egger.coef","egger.qstatistic","egger.df","egger.outliers","egger.data","egger.confint") 68 | 69 | transeg<-(r_object$data$BetaWj/r_object$data$Wj)-(r_object$egger.coef[1,1]/r_object$data$Wj) 70 | 71 | betavec<-c(r_object$data$BetaWj/r_object$data$Wj,transeg) 72 | Wj<-c(r_object$data$Wj,r_object$data$Wj) 73 | tran.indicator<-c(rep("Variant",length(betavec)/2),rep("Egger transform",length(betavec)/2)) 74 | 75 | temp<-data.frame(betavec,Wj,tran.indicator) 76 | 77 | 78 | #Produce plot showing full scale and all variants 79 | B <-ggplot(temp,aes(x=betavec,y=Wj))+labs(title="Radial Funnel Plot")+ geom_point(aes(colour=tran.indicator))+ 80 | theme_bw()+theme(panel.border = element_blank(),panel.grid.major = element_blank(),panel.grid.minor = element_blank(), 81 | axis.line = element_line(colour = "black"))+xlab(expression(hat(beta)[j]))+ylab(expression(sqrt(W[j])))+ 82 | geom_segment(aes(x = r_object$IVW.coef[1], xend = r_object$IVW.coef[1], y = -.5, yend = max(r_object$data$Wj),colour="IVW Estimate"))+ 83 | geom_segment(aes(x = r_object$egger.coef[2,1], xend = r_object$egger.coef[2,1], y = 0, yend = max(r_object$data$Wj),colour="Egger Estimate"))+ 84 | geom_segment(aes(x = r_object$egger.confint[1], xend = r_object$egger.confint[2], y = 0, yend = 0,colour="Egger Estimate"))+ 85 | geom_segment(aes(x = r_object$IVW.confint[1], xend = r_object$IVW.confint[2], y = -.5, yend = -.5,colour="IVW Estimate"))+ 86 | scale_y_continuous(limits = c(-1,max(r_object$data$Wj)))+ 87 | scale_color_manual(name="",breaks=c("Variant","Egger transform","IVW Estimate","Egger Estimate"),values=c("Variant"="black","Egger transform"="#D55E00","IVW Estimate"="#56B4E9","Egger Estimate"="#D55E00"))+ 88 | geom_text(x=r_object$IVW.coef[1], y=-0.7,label=paste(round(r_object$IVW.coef[1],digits=3),paste("(",round(r_object$IVW.confint[1],digits=2),",",round(r_object$IVW.confint[2],digits=2),")"),collapse=""),size=3)+ 89 | geom_text(x=r_object$egger.coef[2,1], y=-0.2,label=paste(round(r_object$egger.coef[2,1],digits=3),paste("(",round(r_object$egger.confint[1],digits=2),",",round(r_object$egger.confint[2],digits=2),")"),collapse=""),size=3) 90 | 91 | 92 | if(show_transform==TRUE){ 93 | 94 | for(i in 1:length(transeg)){ 95 | 96 | B <- B + geom_segment(x = temp$betavec[i], xend = temp$betavec[i+length(transeg)], y = temp$Wj[i], yend = temp$Wj[i],linetype="dotted") 97 | 98 | } 99 | 100 | } 101 | 102 | } 103 | 104 | 105 | return(B) 106 | 107 | } 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | -------------------------------------------------------------------------------- /R/ivw_mvmr.R: -------------------------------------------------------------------------------- 1 | #' ivw_mvmr 2 | #' 3 | #' Fits an IVW multivariable Mendelian randomization model using first order weights. 4 | #' 5 | #' @param r_input A formatted data frame using the \code{format_mvmr} function. 6 | #' @param gencov Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default. 7 | #' 8 | #' @return An dataframe containing MVMR results, including estimated coefficients, their standard errors, t-statistics, and corresponding (two-sided) p-values. 9 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 10 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 11 | #'@export 12 | #'@examples 13 | #' 14 | #' ivw_mvmr(r_input) 15 | #' 16 | 17 | # Define IVW Multivariable MR function: This takes the formatted dataframe from 18 | # the format_MVMR function as an input, as well as the covariance between the effect of the 19 | # genetic variants on each exposure. 20 | 21 | ivw_mvmr<-function(r_input,gencov){ 22 | 23 | #If weights is missing, first order weights are used by default. 24 | 25 | 26 | # Inverse variance weighting is used. 27 | 28 | Wj<-1/r_input[,3]^2 29 | 30 | #Determine the number of exposures included in the model 31 | 32 | exp.number<-length(names(r_input)[-c(1,2,3)])/2 33 | 34 | #Fit the IVW MVMR model 35 | 36 | A_sum<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 37 | seq(4,3+exp.number,by=1)], collapse="+"))) 38 | ,weights=Wj,data=r_input)) 39 | 40 | A<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 41 | seq(4,3+exp.number,by=1)], collapse="+"))) 42 | ,weights=Wj,data=r_input))$coef 43 | 44 | #Rename the regressors for ease of interpretation 45 | for(i in 1:exp.number){ 46 | dimnames(A)[[1]][i]<- paste0("exposure",i,collapse="") 47 | } 48 | 49 | 50 | ########## 51 | # Output # 52 | ########## 53 | 54 | # Print a few summary elements that are common to both lm and plm model summary objects 55 | cat("\n") 56 | 57 | cat("Multivariable MR\n") 58 | 59 | cat("\n") 60 | 61 | print(A) 62 | 63 | cat("\nResidual standard error:", round(A_sum$sigma,3), "on", A_sum$df[2], "degrees of freedom") 64 | 65 | cat("\n") 66 | 67 | cat("\n") 68 | 69 | cat("\n") 70 | 71 | 72 | return(A) 73 | 74 | } -------------------------------------------------------------------------------- /R/ivw_radial.R: -------------------------------------------------------------------------------- 1 | #' ivw_radial 2 | #' 3 | #' Fits a radial inverse variance weighted (IVW) model using first order, second order, or modified second order weights. Outliers are identified using a significance threshold specified by the user. The function returns an object of class \code{"IVW"}, containing regression estimates, a measure of total heterogeneity using Cochran's Q statistic, the individual contribution to overall heterogeneity of each variant, and a data frame for use in constructing the radial plot. 4 | #' 5 | #' @param r_input A formatted data frame using the \code{format_radial} function. 6 | #' @param alpha A value specifying the statistical significance threshold for identifying outliers (\code{0.05} specifies a p-value threshold of 0.05). 7 | #' @param weights A value specifying the inverse variance weights used to calculate IVW estimate and Cochran's Q statistic. By default modified second order weights are used, but one can choose to select first order (\code{1}), second order (\code{2}) or modified second order weights (\code{3}). 8 | #' @param tol A value indicating the tolerance threshold for performing the iterative IVW approach. The value represents the minimum difference between the coefficients of the previous and current iterations required for a further iteration to be performed (default= \code{0.0001}). 9 | #' @return An object of class \code{"IVW"} containing the following components:\describe{ 10 | #' \item{\code{coef}}{The estimated coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 11 | #' \item{\code{qstatistic}}{Cochran's Q statistic for overall heterogeneity.} 12 | #' \item{\code{df}}{Degrees of freedom. This is equal to the number of variants -1 when fitting the radial IVW model.} 13 | #' \item{\code{outliers}}{A data frame containing variants identified as outliers, with respective Q statistics, chi-squared tests and SNP identification.} 14 | #' \item{\code{data}}{A data frame containing containing SNP IDs, inverse variance weights, the product of the inverse variance weight and ratio estimate for each variant, contribution to overall heterogeneity with corresponding p-value, and a factor indicator showing outlier status.} 15 | #' \item{\code{confint}}{A vector giving lower and upper confidence limits for the radial IVW effect estimate.} 16 | #' \item{\code{it.coef}}{The estimated iterative coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 17 | #' \item{\code{it.confint}}{A vector giving lower and upper confidence limits for the iterative radial IVW effect estimate.} 18 | #' \item{\code{fe.coef}}{The estimated fixed effect exact coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 19 | #' \item{\code{fe.confint}}{A vector giving lower and upper confidence limits for the fixed effect exact radial IVW effect estimate.} 20 | #' \item{\code{re.coef}}{The estimated random effect exact coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 21 | #' \item{\code{re.confint}}{A vector giving lower and upper confidence limits for the random effect exact radial IVW effect estimate.} 22 | #' \item{\code{mf}}{The mean F statistic for the set of genetic variants, indicative of instrument strength.} 23 | #' 24 | #'} 25 | #'@author Wes Spiller; Jack Bowden. 26 | #'@references Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 27 | #'@export 28 | #'@examples 29 | #' 30 | #' ivw_radial(r_input,0.05,1,0.0001,T) 31 | #' 32 | 33 | 34 | ivw_radial<-function(r_input,alpha,weights,tol){ 35 | 36 | #Define ratio estimates 37 | Ratios<-r_input[,3]/r_input[,2] 38 | 39 | F<- r_input[,2]^2/r_input[,4]^2 40 | mf<- mean(F) 41 | 42 | cat() 43 | 44 | if(missing(alpha)) { 45 | alpha<-0.05 46 | warning("Significance threshold for outlier detection not specified: Adopting a 95% threshold") 47 | } 48 | 49 | if(missing(weights)) { 50 | weights<-3 51 | warning("Weights not specified: Adopting modified second-order weights") 52 | } 53 | 54 | if(missing(tol)) { 55 | tol<-0.00001 56 | } 57 | 58 | summary<-TRUE 59 | 60 | 61 | if(weights==1){ 62 | 63 | #Define inverse variance weights 64 | W<-((r_input[,2]^2)/(r_input[,5]^2)) 65 | 66 | } 67 | 68 | if(weights==2){ 69 | 70 | #Define inverse variance weights 71 | W<-((r_input[,5]^2/r_input[,2]^2)+((r_input[,3]^2*r_input[,4]^2)/r_input[,2]^4))^-1 72 | 73 | } 74 | 75 | if(weights==3){ 76 | 77 | #Define inverse variance weights 78 | W<-((r_input[,2]^2)/(r_input[,5]^2)) 79 | 80 | } 81 | 82 | #Define vector of squared weights 83 | Wj<-sqrt(W) 84 | 85 | #Define vector of weights * ratio estimates 86 | BetaWj<-Ratios*Wj 87 | 88 | #Define IVW Model 89 | IVW.Model<-lm(BetaWj~-1+Wj) 90 | 91 | #Define output of IVW.Model fit 92 | EstimatesIVW<-summary(lm(IVW.Model)) 93 | 94 | #Define slope parameter for IVW.Model 95 | IVW.Slope<-EstimatesIVW$coefficients[1] 96 | 97 | #Define standard error for slope parameter of IVW.Model 98 | IVW.SE<-EstimatesIVW$coefficients[2] 99 | 100 | #Define confidence interval for IVW.Model slope parameter 101 | IVW_CI<-confint(IVW.Model) 102 | 103 | DF<-length(r_input[,1])-1 104 | 105 | #Define Q statistic for each individual variant 106 | Qj<-W*(Ratios-IVW.Slope)^2 107 | 108 | #Define total Q statistic 109 | Total_Q<-sum(Qj) 110 | 111 | #Perform chi square test for overall Q statistic 112 | Total_Q_chi<-pchisq(Total_Q,length(r_input[,2])-1,lower.tail = FALSE) 113 | 114 | if(weights==3){ 115 | #Define inverse variance weights 116 | W<- ((r_input[,5]^2+(IVW.Slope^2*r_input[,4]^2))/r_input[,2]^2)^-1 117 | 118 | #Define vector of squared weights 119 | Wj<-sqrt(W) 120 | 121 | #Define vector of weights * ratio estimates 122 | BetaWj<-Ratios*Wj 123 | 124 | #Define IVW Model 125 | IVW.Model<-lm(BetaWj~-1+Wj) 126 | 127 | #Define output of IVW.Model fit 128 | EstimatesIVW<-summary(lm(BetaWj~-1+Wj)) 129 | 130 | #Define slope parameter for IVW.Model 131 | IVW.Slope<-EstimatesIVW$coefficients[1] 132 | 133 | #Define standard error for slope parameter of IVW.Model 134 | IVW.SE<-EstimatesIVW$coefficients[2] 135 | 136 | #Define confidence interval for IVW.Model slope parameter 137 | IVW_CI<-confint(IVW.Model) 138 | 139 | #Define Q statistic for each individual variant 140 | Qj<-W*(Ratios-IVW.Slope)^2 141 | 142 | #Define total Q statistic 143 | Total_Q<-sum(Qj) 144 | 145 | #Perform chi square test for overall Q statistic 146 | Total_Q_chi<-pchisq(Total_Q,length(r_input[,2])-1,lower.tail = FALSE) 147 | 148 | } 149 | 150 | Iterative_ivw<-function(int.tol){ 151 | Diff <- 1 152 | Bhat1.Iterative <- 0 153 | count <- 0 154 | while(Diff >= tol){ 155 | 156 | W <- 1/(r_input[,5]^2/r_input[,2]^2 + (Bhat1.Iterative^2)*r_input[,4]^2/r_input[,2]^2) 157 | 158 | #Define vector of squared weights 159 | Wj<-sqrt(W) 160 | 161 | #Define vector of weights * ratio estimates 162 | BetaWj<-Ratios*Wj 163 | 164 | #Define IVW Model 165 | new.IVW.Model<-lm(BetaWj~-1+Wj) 166 | 167 | #Define output of IVW.Model fit 168 | new.EstimatesIVW<-summary(lm(BetaWj~-1+Wj)) 169 | 170 | #Define slope parameter for IVW.Model 171 | new.IVW.Slope<-new.EstimatesIVW$coefficients[1] 172 | 173 | #Define standard error for slope parameter of IVW.Model 174 | new.IVW.SE<-new.EstimatesIVW$coefficients[2] 175 | 176 | #Define confidence interval for IVW.Model slope parameter 177 | new.IVW_CI<-confint(new.IVW.Model) 178 | 179 | #Define Q statistic for each individual variant 180 | new.Qj<-W*(Ratios-new.IVW.Slope)^2 181 | 182 | #Define total Q statistic 183 | new.Total_Q<-sum(new.Qj) 184 | 185 | #Perform chi square test for overall Q statistic 186 | new.Total_Q_chi<-pchisq(new.Total_Q,length(r_input[,2])-1,lower.tail = FALSE) 187 | 188 | Diff <- abs(Bhat1.Iterative - new.IVW.Slope) 189 | Bhat1.Iterative <- new.IVW.Slope 190 | Bhat1.SE<-new.IVW.SE 191 | #Bhat1.CI<-new.IVW_CI 192 | Bhat1.t<-summary(new.IVW.Model)$coefficients[1,3] 193 | Bhat1.p<-summary(new.IVW.Model)$coefficients[1,4] 194 | count <- count+1 195 | } 196 | 197 | It.Dat<-data.frame(Bhat1.Iterative,Bhat1.SE,Bhat1.t,Bhat1.p) 198 | 199 | multi_return2 <- function() { 200 | Out_list2 <- list("It.Res" = It.Dat,"count"= count,"It.CI"=new.IVW_CI) 201 | 202 | return(Out_list2) 203 | } 204 | OUT2<-multi_return2() 205 | 206 | 207 | } 208 | 209 | Bhat1.Iterative<-Iterative_ivw(tol) 210 | 211 | ###################EXACT WEIGHTS###################### 212 | 213 | PL2 = function(a){ 214 | b = a[1] 215 | w = 1/((phi)*r_input[,5]^2/r_input[,2]^2 + (b^2)*r_input[,4]^2/r_input[,2]^2) 216 | q = sum(w*(Ratios - b)^2) 217 | } 218 | 219 | PLfunc = function(a){ 220 | phi = a[1] 221 | PL2 = function(a){ 222 | beta = a[1] 223 | w = 1/(phi*r_input[,5]^2/r_input[,2]^2 + (beta^2)*r_input[,4]^2/r_input[,2]^2) 224 | q = (sum(w*(Ratios - beta)^2)) 225 | }# 226 | b = optimize(PL2,interval=c(lb,ub))$minimum 227 | w = 1/(phi*r_input[,5]^2/r_input[,2]^2 + (b^2)*r_input[,4]^2/r_input[,2]^2) 228 | q = (sum(w*(Ratios - b)^2) - DF)^2 229 | } 230 | 231 | BootVar = function(sims=1000){ 232 | B = NULL ; pp=NULL 233 | for(hh in 1:sims){ 234 | L = length(r_input[,2]) 235 | choice = sample(seq(1,L),L,replace=TRUE) 236 | bxg = r_input[,2][choice] ; seX = r_input[,4][choice] 237 | byg = r_input[,3][choice] ; seY = r_input[,5][choice] 238 | Ratios = byg/bxg 239 | 240 | W1 = 1/(seY^2/bxg^2) 241 | BIVw1 = Ratios*sqrt(W1) 242 | sW1 = sqrt(W1) 243 | IVWfitR1 = summary(lm(BIVw1 ~ -1+sW1)) 244 | phi_IVW1 = IVWfitR1$sigma^2 245 | W2 = 1/(seY^2/bxg^2 + (byg^2)*seX^2/bxg^4) 246 | BIVw2 = Ratios*sqrt(W2) 247 | sW2 = sqrt(W2) 248 | IVWfitR2 = summary(lm(BIVw2 ~ -1+sW2)) 249 | phi_IVW2 = IVWfitR2$sigma^2 250 | 251 | phi_IVW2 = max(1,phi_IVW2) 252 | phi_IVW1 = max(1,phi_IVW1) 253 | lb = IVWfitR1$coef[1] - 10*IVWfitR1$coef[2] 254 | ub = IVWfitR1$coef[1] + 10*IVWfitR1$coef[2] 255 | 256 | PL2 = function(a){ 257 | b = a[1] 258 | w = 1/((phi)*seY^2/bxg^2 + (b^2)*seX^2/bxg^2) 259 | q = sum(w*(Ratios - b)^2) 260 | } 261 | 262 | PLfunc = function(a){ 263 | phi = a[1] 264 | PL2 = function(a){ 265 | beta = a[1] 266 | w = 1/(phi*seY^2/bxg^2 + (beta^2)*seX^2/bxg^2) 267 | q = (sum(w*(Ratios - beta)^2)) 268 | } 269 | b = optimize(PL2,interval=c(-lb,ub))$minimum 270 | w = 1/(phi*seY^2/bxg^2 + (b^2)*seX^2/bxg^2) 271 | q = (sum(w*(Ratios - b)^2) - DF)^2 272 | } 273 | phi = optimize(PLfunc,interval=c(phi_IVW2,phi_IVW1+0.001))$minimum 274 | B[hh] = optimize(PL2,interval=c(lb,ub))$minimum 275 | } 276 | se = sd(B) 277 | mB = mean(B) 278 | return(list(mB=mB,se=se)) 279 | } 280 | 281 | CIfunc = function(){ 282 | z = qt(df=DF, 0.975) 283 | z2 = 2*(1-pnorm(z)) 284 | 285 | PL3 = function(a){ 286 | b = a[1] 287 | w = 1/(r_input[,5]^2/r_input[,2]^2 + (b^2)*r_input[,4]^2/r_input[,2]^2) 288 | q = (sum(w*(Ratios - b)^2) - qchisq(1-z2,DF))^2 289 | } 290 | 291 | lb = Bhat - 10*SE 292 | ub = Bhat + 10*SE 293 | 294 | low = optimize(PL3,interval=c(lb,Bhat))$minimum 295 | high = optimize(PL3,interval=c(Bhat,ub))$minimum 296 | CI = c(low,high) 297 | return(list(CI=CI)) 298 | } 299 | 300 | 301 | ####################### 302 | # Fixed effect model # 303 | # and Exact Q test # 304 | ####################### 305 | 306 | phi = 1 307 | Bhat = optimize(PL2,interval=c(-2,2))$minimum 308 | W = 1/(r_input[,5]^2/r_input[,2]^2 + (Bhat^2)*r_input[,4]^2/r_input[,2]^2) 309 | SE = sqrt(1/sum(W)) 310 | FCI = CIfunc() 311 | 312 | # Qtest 313 | 314 | QIVW = sum(W*(Ratios - Bhat)^2) 315 | Qp = 1-pchisq(QIVW,DF) 316 | Qind = W*(Ratios - Bhat)^2 317 | ExactQ = c(QIVW,Qp) 318 | ExactQind = Qind 319 | # Estimation (fixed effects) 320 | # point estimate, se, t-stat, p-value) 321 | 322 | FE_EXACT = t(c(Bhat,SE,Bhat/SE,2*(1-pt(abs(Bhat/SE),DF)))) 323 | 324 | FE_EXACT<-data.frame(FE_EXACT) 325 | 326 | names(FE_EXACT)<-c("Estimate","Std.Error","t value","Pr(>|t|)") 327 | 328 | ######################## 329 | # Random effect model # 330 | # and Exact Q test # 331 | ######################## 332 | 333 | BIVW1 = Ratios*sqrt(1/(r_input[,5]^2/r_input[,2]^2)) 334 | IVWfit1 = summary(lm(BIVW1 ~ -1+sqrt(1/(r_input[,5]^2/r_input[,2]^2)))) 335 | phi_IVW1 = IVWfit1$sigma^2 336 | 337 | 338 | BIVW2 <- Ratios*sqrt(1/(r_input[,5]^2/r_input[,2]^2 + (r_input[,3]^2)*r_input[,4]^2/r_input[,2]^4)) 339 | IVWfit2 = summary(lm(BIVW2 ~ -1+sqrt(1/(r_input[,5]^2/r_input[,2]^2 + (r_input[,3]^2)*r_input[,4]^2/r_input[,2]^4)))) 340 | 341 | phi_IVW2 = IVWfit2$sigma^2 342 | 343 | phi_IVW2 = max(1,phi_IVW2) 344 | phi_IVW1 = max(1,phi_IVW1)+0.001 345 | 346 | lb = Bhat - 10*SE 347 | ub = Bhat + 10*SE 348 | 349 | phi = optimize(PLfunc,interval=c(phi_IVW2,phi_IVW1))$minimum 350 | Bhat = optimize(PL2,interval=c(lb,ub))$minimum 351 | Boot = BootVar() 352 | SE = Boot$se 353 | 354 | # point estimate, se, t-stat, p-value) 355 | 356 | RCI = Bhat + c(-1,1)*qt(df=DF, 0.975)*SE 357 | RE_EXACT = t(c(Bhat,SE,Bhat/SE,2*(1-pt(abs(Bhat/SE),DF)))) 358 | 359 | RE_EXACT<-data.frame(RE_EXACT) 360 | names(RE_EXACT)<-c("Estimate","Std.Error","t value","Pr(>|t|)") 361 | 362 | #Define a placeholder vector of 0 values for chi square tests 363 | Qj_Chi<-0 364 | 365 | #Perform chi square tests for each Qj value 366 | for(i in 1:length(Qj)){ 367 | Qj_Chi[i]<-pchisq(Qj[i],1,lower.tail = FALSE) 368 | } 369 | 370 | #Define dataframe with SNP IDs and outlier statistics 371 | r_input$Qj<-Qj 372 | r_input$Qj_Chi<-Qj_Chi 373 | 374 | #Define a placeholder vector of 0 values for identifying outliers 375 | Out_Indicator<-rep(0,length(r_input[,2])) 376 | 377 | #For loop defining outlier indicator variable. 378 | for( i in 1:length(r_input[,2])){ 379 | if(Qj_Chi[i]0)){ 398 | outlier_status<-"Outliers detected" 399 | 400 | #Generate a subset of data containing only outliers 401 | Out_Dat<-subset(r_input, Outliers == "Outlier") 402 | 403 | #Construct a datafrae containing SNP IDs, Q statistics and chi-square values for each outlying variant 404 | outtab<-data.frame(Out_Dat[,1],Out_Dat$Qj,Out_Dat$Qj_Chi) 405 | 406 | #Redefine column names 407 | colnames(outtab) = c("SNP","Q_statistic","p.value") 408 | 409 | } 410 | 411 | if(summary==TRUE){ 412 | 413 | # Print a few summary elements that are common to both lm and plm model summary objects 414 | cat("\n") 415 | 416 | cat("Radial IVW\n") 417 | 418 | cat("\n") 419 | 420 | Sum.Dat<-data.frame(coef(EstimatesIVW)) 421 | names(Sum.Dat)<-c("Estimate","Std.Error","t value","Pr(>|t|)") 422 | names(Bhat1.Iterative$It.Res)<-names(Sum.Dat) 423 | combined.dat<-(rbind(Sum.Dat,Bhat1.Iterative$It.Res)) 424 | combined.dat<-rbind(combined.dat,FE_EXACT) 425 | combined.dat<-rbind(combined.dat,RE_EXACT) 426 | 427 | for(i in 1:3){ 428 | combined.dat[i,4]<- 2 * pnorm(abs(combined.dat[i,1]/combined.dat[i,2]), low = FALSE) 429 | } 430 | 431 | 432 | row.names(combined.dat)<-c("Effect","Iterative","Exact (FE)","Exact (RE)") 433 | 434 | if(weights == 1){ 435 | 436 | row.names(combined.dat)[1] <- "Effect (1st)" 437 | 438 | } 439 | 440 | if(weights == 2){ 441 | 442 | row.names(combined.dat)[1] <- "Effect (2nd)" 443 | 444 | } 445 | 446 | if(weights == 3){ 447 | 448 | row.names(combined.dat)[1] <- "Effect (Mod.2nd)" 449 | 450 | } 451 | 452 | 453 | print(combined.dat) 454 | 455 | cat("\n") 456 | 457 | cat("\nResidual standard error:", round(EstimatesIVW$sigma,3), "on", EstimatesIVW$df[2], "degrees of freedom") 458 | 459 | cat("\n") 460 | 461 | cat(paste(c("\nF-statistic:", " on"," and"), round(EstimatesIVW$fstatistic,2), collapse=""), 462 | "DF, p-value:", 463 | format.pval(pf(EstimatesIVW$fstatistic[1L], EstimatesIVW$fstatistic[2L], EstimatesIVW$fstatistic[3L], 464 | lower.tail = FALSE), digits=3)) 465 | 466 | cat("\n") 467 | 468 | cat("Q-Statistic for heterogeneity:",Total_Q, "on", length(r_input[,2])-1, "DF",",", "p-value:" , Total_Q_chi) 469 | 470 | cat("\n") 471 | 472 | cat("\n",outlier_status,"\n") 473 | cat("Number of iterations =", Bhat1.Iterative$count) 474 | cat("\n") 475 | 476 | } 477 | 478 | out_data<-data.frame(r_input[,1],r_input[,6],r_input[,7],r_input[,8]) 479 | out_data$Wj<-Wj 480 | out_data$BetaWj<-BetaWj 481 | out_data<-out_data[c(1,5,6,2,3,4)] 482 | names(out_data)<-c("SNP","Wj","BetaWj","Qj","Qj_Chi","Outliers") 483 | 484 | multi_return <- function() { 485 | Out_list <- list("coef" = combined.dat,"qstatistic"= Total_Q, "df" = length(r_input[,2])-1, "outliers" = outtab, "data" = out_data, "confint" = confint(IVW.Model), 486 | "it.coef"=combined.dat[2,],"fe.coef"=combined.dat[3,],"re.coef" = combined.dat[4,1], "it.confint"= Bhat1.Iterative$It.CI,"fe.confint" = FCI$CI, "re.confint" = RCI, "meanF"= mf) 487 | class(Out_list)<-"IVW" 488 | 489 | return(Out_list) 490 | } 491 | OUT<-multi_return() 492 | 493 | 494 | } 495 | -------------------------------------------------------------------------------- /R/mvmr.R: -------------------------------------------------------------------------------- 1 | #' mvmr (legacy) 2 | #' 3 | #' Note: This function is from the old version of the MVMR package and will be replaced in the future: The gencov argument should be set to zero when using \code{mvmr()}. 4 | #' 5 | #' Fits an IVW multivariable Mendelian randomization model using first order weights. The function returns an object of class \code{"MVMRIVW"}, containing regression estimates, estimated heterogeneity as a measure of instrument strength (\code{Q_strength}), and estimated heterogeneity as a measure of instrument validity (\code{Q_valid}). 6 | #' 7 | #' @param r_input A formatted data frame using the \code{format_mvmr} function. 8 | #' @param gencov Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default. 9 | #' @param weights A value specifying the inverse variance weights used to calculate IVW estimate and Cochran's Q statistic. Currently only first order weights are available (\code{1}). 10 | #' 11 | #' @return An object of class \code{"MVMRIVW"} containing the following components:\describe{ 12 | #' \item{\code{summary}}{A summary of the MVMR regression model, including estimated coefficients, standard errors, t-statistics, p-values, and heterogeneity statistics.} 13 | #' \item{\code{coef}}{The estimated coefficients, their standard errors, t-statistics, and corresponding (two-sided) p-values.} 14 | #' \item{\code{Q_strength}}{A data frame displaying modified Cochran's Q statistics for assessing instrument strength with respect to each exposure. The Q-statistic increases proportionally with instrument strength, and analogous to univariate MR analyses, a value equal to or greater than 10 can be used as a minimum threshold for instrument strength. Note that for these statistics it is not informative to evaluate p-values.} 15 | #' \item{\code{Q_valid}}{A modified form of Cochran's Q statistic measuring heterogeneity in causal effect estimates obtained using each genetic variant. Observed heterogeneity is indicative of a violation of the exclusion restriction assumption in MR (validity), which can result in biased effect estimates.} 16 | #' \item{\code{p_valid}}{A p-value corresponding to the heterogeneity measure for instrument validity (\code{Q_valid})} 17 | #'} 18 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 19 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 20 | #'@export 21 | #'@examples 22 | #' 23 | #' mvmr(r_input,0,1) 24 | #' 25 | 26 | # Define IVW Multivariable MR function: This takes the formatted dataframe from 27 | # the format_MVMR function, as an input, the covariance between the effect of the 28 | # genetic variants on each exposure, and a value indicating the weights to 29 | # used in the analysis. 30 | 31 | mvmr<-function(r_input,gencov,weights){ 32 | 33 | #gencov is the covariance between the effect of the genetic variants on each exposure. 34 | #By default it is set to 0. 35 | 36 | if(missing(gencov)) { 37 | gencov<-0 38 | warning("Covariance between effect of genetic variants on each exposure not specified. Fixing covariance at 0.") 39 | } 40 | 41 | #If weights is missing, first order weights are used by default. 42 | 43 | if(missing(weights)) { 44 | weights<-1 45 | warning("Weights not specified: Adopting first-order weights") 46 | } 47 | 48 | # A value of 1 for weights indicates inverse variance weighting is to be used. 49 | 50 | if(weights==1){ 51 | Wj<-1/r_input[,3]^2 52 | } 53 | 54 | #Determine the number of exposures included in the model 55 | 56 | exp.number<-length(names(r_input)[-c(1,2,3)])/2 57 | 58 | #Fit the IVW MVMR model 59 | 60 | A_sum<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 61 | seq(4,3+exp.number,by=1)], collapse="+"))) 62 | ,weights=Wj,data=r_input)) 63 | 64 | A<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 65 | seq(4,3+exp.number,by=1)], collapse="+"))) 66 | ,weights=Wj,data=r_input))$coef 67 | 68 | #Rename the regressors for ease of interpretation 69 | for(i in 1:exp.number){ 70 | dimnames(A)[[1]][i]<- paste0("exposure",i,collapse="") 71 | } 72 | 73 | ############################################# 74 | # Generalised instrument strength het.stats # 75 | ############################################# 76 | 77 | #Create an empty matrix for delta value (coefficients regressing each set of exposure effects upon other 78 | #exposure effects) 79 | 80 | delta_mat<-matrix(0,ncol=exp.number,nrow=exp.number-1) 81 | 82 | #Obtain delta values fitting regression models for each set of exposure effects upon other exposure effects 83 | for(i in 1:exp.number){ 84 | regressand<-names(r_input[3 + i]) 85 | regressors<-names(r_input)[-c(1,2,3, 86 | 4+exp.number:length(names(r_input)))] 87 | C<-paste(regressand, "~", "-1 +", paste(regressors[-i], collapse="+")) 88 | D.reg<-lm(C,data=r_input) 89 | delta_mat[,i]<-D.reg$coefficients 90 | } 91 | 92 | #Create an empty matrix for sigma2xj values 93 | sigma2xj_dat<-matrix(ncol=exp.number,nrow=length(r_input[,1]),0) 94 | 95 | #Create a subset containing only standard errors for exposure effect estimates 96 | sebetas<-r_input[,(exp.number + 4):length(r_input)] 97 | 98 | #Generates the sigma2xj values for each exposure 99 | for(i in 1:exp.number){ 100 | se.temp<-as.matrix(sebetas[,-i]) 101 | for(j in 1:(exp.number-1)){ 102 | sigma2xj_dat[,i]<- sigma2xj_dat[,i] + (se.temp[,j]^2 * delta_mat[j,i]^2) 103 | } 104 | sigma2xj_dat[,i]<- sigma2xj_dat[,i] + sebetas[,i]^2 - gencov 105 | 106 | } 107 | 108 | #Create an empty matrix for instrument strength Q statistics 109 | Q_strength<-matrix(ncol=exp.number,nrow=1,0) 110 | 111 | #Generates the component of the Q statistic to be subtracted from the exposure estimates 112 | for(i in 1:exp.number){ 113 | betas<-r_input[,c(4:(3+exp.number))] 114 | betas<-data.frame(betas[,-i]) 115 | temp.sub <- 0 116 | for(j in 1:(exp.number-1)){ 117 | temp.sub<-temp.sub + (delta_mat[j,i] * betas[,j]) 118 | } 119 | 120 | #Populates matrix of Q statistics with respect to instrument strength 121 | Q_strength[i]<- sum( (1/sigma2xj_dat[,i]) * ((r_input[,3+i] - temp.sub)^2) ) 122 | } 123 | 124 | Q_strength<-data.frame(Q_strength) 125 | names(Q_strength)<-dimnames(A)[[1]] 126 | rownames(Q_strength)<-"Q" 127 | 128 | ######################## 129 | ## Instrument Validity # 130 | ######################## 131 | 132 | # Generate Sigma^2_A values 133 | sigma2A<-r_input[,3]^2 134 | for(i in 1:exp.number){ 135 | sigma2A<-sigma2A + (A[i]^2 * sebetas[,i]^2) 136 | } 137 | 138 | if(gencov != 0){ 139 | 140 | warning("Validity statistics do not currently account for covariance between the effect of the genetic variants on each exposure") 141 | 142 | } 143 | 144 | #Create a subset of exposure effect estimates 145 | betas<-r_input[,c(4:(3+exp.number))] 146 | 147 | #Generates the component of the Q statistic to be subtracted from the outcome estimates 148 | temp.sub2<-0 149 | for(i in 1:exp.number){ 150 | temp.sub2<-temp.sub2 + (betas[,i] * A[i]) 151 | } 152 | 153 | #Calculates Q statistic for instrument validity 154 | Q_valid<- sum ((1/sigma2A)*(r_input[,2]-temp.sub2)^2) 155 | 156 | #Calculates p_value for instrument validity 157 | Q_chiValid<-pchisq(Q_valid,length(r_input[,2])-exp.number-1,lower.tail = FALSE) 158 | 159 | ########## 160 | # Output # 161 | ########## 162 | 163 | # Print a few summary elements that are common to both lm and plm model summary objects 164 | cat("\n") 165 | 166 | cat("Multivariable MR\n") 167 | 168 | cat("\n") 169 | 170 | print(A) 171 | 172 | cat("\nResidual standard error:", round(A_sum$sigma,3), "on", A_sum$df[2], "degrees of freedom") 173 | 174 | cat("\n") 175 | 176 | cat(paste(c("\nF-statistic:", " on"," and"), round(A_sum$fstatistic,2), collapse=""), 177 | "DF, p-value:", 178 | format.pval(pf(A_sum$fstatistic[1L], A_sum$fstatistic[2L], A_sum$fstatistic[3L], 179 | lower.tail = FALSE), digits=3)) 180 | 181 | cat("\n") 182 | 183 | cat("\n") 184 | 185 | cat("------------------------------") 186 | 187 | cat("\n") 188 | 189 | cat("Q-Statistics for instrument strength:") 190 | 191 | cat("\n") 192 | 193 | cat("\n") 194 | 195 | print(Q_strength) 196 | 197 | cat("\n") 198 | 199 | cat("------------------------------") 200 | 201 | cat("\n") 202 | 203 | cat("Q-Statistic for instrument validity:") 204 | 205 | cat("\n") 206 | 207 | cat("\n") 208 | 209 | cat(Q_valid, "on", length(r_input[,2])-exp.number-1, "DF",",", "p-value:" , Q_chiValid) 210 | 211 | cat("\n") 212 | 213 | 214 | #A function allowing multiple objects to be accessed from the output object 215 | multi_return <- function() { 216 | Out_list <- list("coef" = A, "Q_strength"=Q_strength, "Q_valid"=Q_valid, "p_valid"=Q_chiValid) 217 | 218 | #Defines class of output object 219 | class(Out_list)<-"MVMRIVW" 220 | return(Out_list) 221 | } 222 | OUT<-multi_return() 223 | } -------------------------------------------------------------------------------- /R/phenocov_mvmr.R: -------------------------------------------------------------------------------- 1 | #' phenocov_mvmr 2 | #' 3 | #' Uses an external phenotypic covariance matrix and summary data to estimate covariance matrices for estimated effects of individual genetic 4 | #' variants on each exposure. The function returns a number of covariance matrices equal to the number of SNPs, where SNP and 5 | #' row numbers reference ordered exposures. 6 | #' 7 | #' @param Pcov A phenotypic matrix using exposures, constructed using individual level exposure data. Columns should be ordered by exposure so as to match \code{format_mvmr}. 8 | #' @param seBXGs A matrix containing standard errors corresponding in relation to the gene-exposure association for each SNP. 9 | #' 10 | #' @return A list of covariance matrices with respect to each genetic variant, retaining the ordering in \code{Gs} 11 | #' 12 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 13 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 14 | #'@export 15 | #'@examples 16 | #' 17 | #' phenocov_mvmr(Pcov,summarydata[,c(3,4)]) 18 | #' 19 | 20 | phenocov_mvmr<-function(Pcov,seBXGs){ 21 | 22 | sigmalist <- vector("list", length(Gs[1,])) 23 | 24 | for(i in 1:length(seBXGs[,1])){ 25 | 26 | sigma_mattemp<-Pcov 27 | 28 | for(j in 1:length(seBXGs[1,])){ 29 | 30 | for(k in 1:length(seBXGs[1,])){ 31 | 32 | sigma_mattemp[j,k]<-sigma_mattemp[j,k] * seBXGs[i,j] * seBXGs[i,k] 33 | 34 | } 35 | 36 | } 37 | 38 | sigmalist[[i]] <-sigma_mattemp 39 | 40 | } 41 | 42 | return(sigmalist) 43 | 44 | } 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /R/pleiotropy_mvmr.R: -------------------------------------------------------------------------------- 1 | #' pleiotropy_mvmr 2 | #' 3 | #' Calculates modified form of Cochran's Q statistic measuring heterogeneity in causal effect estimates obtained using each genetic variant. Observed heterogeneity is indicative of a violation of the exclusion restriction assumption in MR (validity), which can result in biased effect estimates. 4 | #' The function takes a formatted dataframe as an input, obtained using the function \code{format_mvmr}. Additionally, covariance matrices 5 | #' for estimated effects of individual genetic variants on each exposure can also be provided. These can be estimated using external data by 6 | #' applying the \code{snpcov_mvmr} or \code{phenocov_mvmr} functions, are input manually. The function returns a dataframe including the conditional 7 | #' Q-statistic for instrument validity, and a corresponding P-value. 8 | #' 9 | #' 10 | #' @param r_input r_input A formatted data frame using the \code{format_mvmr} function. 11 | #' @param gencov Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default. 12 | #' 13 | #' @return A Q-statistic for instrument validity and the corresponding p-value 14 | #' 15 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 16 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 17 | #'@export 18 | #'@examples 19 | #' 20 | #' pleiotropy_mvmr(data,covariances) 21 | #' 22 | 23 | pleiotropy_mvmr<-function(r_input,gencov){ 24 | 25 | #gencov is the covariance between the effect of the genetic variants on each exposure. 26 | #By default it is set to 0. 27 | 28 | if(missing(gencov)) { 29 | gencov<-0 30 | warning("Covariance between effect of genetic variants on each exposure not specified. Fixing covariance at 0.") 31 | } 32 | 33 | # Inverse variance weighting is used. 34 | 35 | Wj<-1/r_input[,3]^2 36 | 37 | #Determine the number of exposures included in the model 38 | 39 | exp.number<-length(names(r_input)[-c(1,2,3)])/2 40 | 41 | #Fit the IVW MVMR model 42 | 43 | A_sum<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 44 | seq(4,3+exp.number,by=1)], collapse="+"))) 45 | ,weights=Wj,data=r_input)) 46 | 47 | A<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 48 | seq(4,3+exp.number,by=1)], collapse="+"))) 49 | ,weights=Wj,data=r_input))$coef 50 | 51 | #Rename the regressors for ease of interpretation 52 | for(i in 1:exp.number){ 53 | dimnames(A)[[1]][i]<- paste0("exposure",i,collapse="") 54 | } 55 | 56 | 57 | #Create a subset containing only standard errors for exposure effect estimates 58 | sebetas<-r_input[,(exp.number + 4):length(r_input)] 59 | 60 | 61 | ######################## 62 | ## Instrument Validity # 63 | ######################## 64 | 65 | if(length(gencov) <2){ 66 | 67 | # Generate Sigma^2_A values 68 | sigma2A<-r_input[,3]^2 69 | for(i in 1:exp.number){ 70 | sigma2A<-sigma2A + (A[i]^2 * sebetas[,i]^2) 71 | } 72 | 73 | #Create a subset of exposure effect estimates 74 | betas<-r_input[,c(4:(3+exp.number))] 75 | 76 | #Generates the component of the Q statistic to be subtracted from the outcome estimates 77 | temp.sub2<-0 78 | for(i in 1:exp.number){ 79 | temp.sub2<-temp.sub2 + (betas[,i] * A[i]) 80 | } 81 | 82 | #Calculates Q statistic for instrument validity 83 | Q_valid<- sum ((1/sigma2A)*(r_input[,2]-temp.sub2)^2) 84 | 85 | #Calculates p_value for instrument validity 86 | Q_chiValid<-pchisq(Q_valid,length(r_input[,2])-exp.number-1,lower.tail = FALSE) 87 | 88 | 89 | } 90 | 91 | if(length(gencov) >2){ 92 | 93 | # Generate Sigma^2_A values 94 | sigma2A<-r_input[,3]^2 95 | for(i in 1:length(r_input[,3])){ 96 | sigma2A[i]<-sigma2A[i] + (t(as.matrix(A[,1])) %*% gencov[[i]]%*% as.matrix(A[,1])) 97 | } 98 | 99 | #Create a subset of exposure effect estimates 100 | betas<-r_input[,c(4:(3+exp.number))] 101 | 102 | #Generates the component of the Q statistic to be subtracted from the outcome estimates 103 | temp.sub2<-0 104 | for(i in 1:exp.number){ 105 | temp.sub2<-temp.sub2 + (betas[,i] * A[i]) 106 | } 107 | 108 | #Calculates Q statistic for instrument validity 109 | Q_valid<- sum ((1/sigma2A)*(r_input[,2]-temp.sub2)^2) 110 | 111 | #Calculates p_value for instrument validity 112 | Q_chiValid<-pchisq(Q_valid,length(r_input[,2])-exp.number-1,lower.tail = FALSE) 113 | 114 | 115 | } 116 | 117 | 118 | ########## 119 | # Output # 120 | ########## 121 | 122 | cat("Q-Statistic for instrument validity:") 123 | 124 | cat("\n") 125 | 126 | cat(Q_valid, "on", length(r_input[,2])-exp.number-1, "DF",",", "p-value:" , Q_chiValid) 127 | 128 | cat("\n") 129 | 130 | multi_return <- function() { 131 | Out_list <- list("Qstat" = Q_valid, "Qpval"=Q_chiValid) 132 | 133 | #Defines class of output object 134 | 135 | return(Out_list) 136 | } 137 | OUT<-multi_return() 138 | } -------------------------------------------------------------------------------- /R/plotly_radial.R: -------------------------------------------------------------------------------- 1 | #' plotly_radial 2 | #' 3 | #' A function for producing interactive radial IVW and MR-Egger plots individually.The function utilises the output from the \code{IVW_radial} and \code{egger_radial} functions. 4 | #' 5 | #' @param r_object An object of class \code{"IVW"} or \code{"egger"}. 6 | #' @return A plotly object containing a radial plot of either the IVW or MR-Egger estimates. Hovering the mouse over individual datapoints will highlight the corresponding SNP identification number for that observation. 7 | #'@author Wes Spiller; Jack Bowden. 8 | #'@references Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 9 | #'@export 10 | #'@examples 11 | #' 12 | #'plotly_radial(r_object) 13 | 14 | plotly_radial<-function(r_object,TEST){ 15 | 16 | if(missing(TEST)) { 17 | TEST<-FALSE 18 | } 19 | 20 | library(plotly) 21 | 22 | if(length(r_object)==13){ 23 | 24 | r_object$coef<-c(r_object$coef[2,]) 25 | r_object$coef<-as.numeric(r_object$coef) 26 | 27 | circle.radial <- function(center = c(0,0), radius, num.points, START,END){ 28 | R = radius 29 | tt <- seq(START,END,length.out = num.points) 30 | #Generates x-axis values for circle 31 | xx <- center[1] + R * cos(tt) 32 | #Generates y-axis values for circle 33 | yy <- center[2] + R * sin(tt) 34 | return(data.frame(x = xx, y = yy)) 35 | } 36 | 37 | maxWj<-max(r_object$data$Wj) 38 | Wjcor<-r_object$data[r_object$data$Wj==maxWj,] 39 | R.IVW<-Wjcor$Wj^2+Wjcor$BetaWj^2 40 | R.IVW<-sqrt(R.IVW)*1.05 41 | IVW_circlemin<-r_object$confint[1] 42 | IVW_circlemax<-r_object$confint[2] 43 | 44 | circledat_IVWEST <- circle.radial(c(0,0),R.IVW,100,atan(IVW_circlemin),atan(IVW_circlemax)) 45 | cxIVW<-circledat_IVWEST$x 46 | cyIVW<-circledat_IVWEST$y 47 | 48 | ay <- list( 49 | zeroline = FALSE, 50 | showline = FALSE, 51 | mirror = "ticks", 52 | gridcolor = toRGB("white"), 53 | gridwidth = 0, 54 | zerolinecolor = toRGB("black"), 55 | zerolinewidth = 1, 56 | linecolor = toRGB("white"), 57 | linewidth = 0, 58 | title = "Beta*sqrt(Wj)" 59 | ) 60 | 61 | ax <- list( 62 | zeroline = TRUE, 63 | showline = FALSE, 64 | mirror = "ticks", 65 | gridcolor = toRGB("white"), 66 | gridwidth = 0, 67 | zerolinecolor = toRGB("black"), 68 | zerolinewidth = 1, 69 | linecolor = toRGB("white"), 70 | linewidth = 0, 71 | title= "sqrt(Wj)" 72 | ) 73 | 74 | if(nrow(r_object$data[r_object$data$Outliers=="Outlier",]) == 0){ 75 | 76 | T_PLOT<- plot_ly(r_object$data, mode="marker", type = 'scatter') %>% 77 | add_trace(x = r_object$data[r_object$data$Outliers=="Variant",]$Wj , y = r_object$data[r_object$data$Outliers=="Variant",]$BetaWj, name = 'Variant', mode = 'markers', marker= list(color="black"),text= r_object$data[r_object$data$Outliers=="Variant",]$SNP, hoverinfo = 'text') %>% 78 | add_trace(x = cxIVW , y = cyIVW, mode = 'line',showlegend=FALSE,name="IVW_CI", line= list(color = "#56B4E9",size=1)) %>% 79 | layout(xaxis = ax,yaxis = ay) %>% 80 | add_segments(x = 0, xend = cos(atan(r_object$coef[1]))*R.IVW, y = 0, yend = sin(atan(r_object$coef[1]))*R.IVW,name = "IVW", line= list(color = "#56B4E9",size=1))%>% 81 | add_annotations(x = c(cxIVW[1],cos(atan(r_object$coef[1]))*R.IVW,cxIVW[100]), 82 | y = c(cyIVW[1],sin(atan(r_object$coef[1]))*R.IVW,cyIVW[100]), 83 | text = c(round(r_object$confint[1],digits=3),round(r_object$coef[1],digits=3),round(r_object$confint[2],digits=3)), 84 | xref = "x", 85 | yref = "y", 86 | showarrow = TRUE, 87 | arrowhead = 0, 88 | arrowsize = 0, 89 | ax = 25, 90 | ay = 1) 91 | 92 | } 93 | 94 | if(nrow(r_object$data[r_object$data$Outliers=="Outlier",]) > 0){ 95 | 96 | T_PLOT<- plot_ly(r_object$data, mode="marker", type = 'scatter') %>% 97 | add_trace(x = r_object$data[r_object$data$Outliers=="Variant",]$Wj , y = r_object$data[r_object$data$Outliers=="Variant",]$BetaWj, name = 'Variant', mode = 'markers', marker= list(color="black"),text= r_object$data[r_object$data$Outliers=="Variant",]$SNP, hoverinfo = 'text') %>% 98 | add_trace(x = r_object$data[r_object$data$Outliers=="Outlier",]$Wj , y = r_object$data[r_object$data$Outliers=="Outlier",]$BetaWj, name = 'Outlier', mode = 'markers', marker= list(color="#E69F00"),text= r_object$data[r_object$data$Outliers=="Outlier",]$SNP, hoverinfo = 'text') %>% 99 | add_trace(x = cxIVW , y = cyIVW, mode = 'line',showlegend=FALSE,name="IVW_CI", line= list(color = "#56B4E9",size=1)) %>% 100 | layout(xaxis = ax,yaxis = ay) %>% 101 | add_segments(x = 0, xend = cos(atan(r_object$coef[1]))*R.IVW, y = 0, yend = sin(atan(r_object$coef[1]))*R.IVW,name = "IVW", line= list(color = "#56B4E9",size=1))%>% 102 | add_annotations(x = c(cxIVW[1],cos(atan(r_object$coef[1]))*R.IVW,cxIVW[100]), 103 | y = c(cyIVW[1],sin(atan(r_object$coef[1]))*R.IVW,cyIVW[100]), 104 | text = c(round(r_object$confint[1],digits=3),round(r_object$coef[1],digits=3),round(r_object$confint[2],digits=3)), 105 | xref = "x", 106 | yref = "y", 107 | showarrow = TRUE, 108 | arrowhead = 0, 109 | arrowsize = 0, 110 | ax = 25, 111 | ay = 1) 112 | 113 | } 114 | 115 | } 116 | 117 | if(length(r_object)==6){ 118 | 119 | if(TEST==T){ 120 | 121 | circle.radial <- function(center = c(0,r_object$coef[1,1]), radius, num.points, START,END){ 122 | R = radius 123 | tt <- seq(START,END,length.out = num.points) 124 | #Generates x-axis values for circle 125 | xx <- center[1] + R * cos(tt) 126 | #Generates y-axis values for circle 127 | yy <- center[2] + R * sin(tt) 128 | return(data.frame(x = xx, y = yy)) 129 | } 130 | 131 | maxWj<-max(r_object$data$Wj) 132 | Wjcor<-r_object$data[r_object$data$Wj==maxWj,] 133 | R.Egger<-Wjcor$Wj^2+Wjcor$BetaWj^2 134 | R.Egger<-sqrt(R.Egger)*1.05 135 | Egger_circlemin<-r_object$confint[1] 136 | Egger_circlemax<-r_object$confint[2] 137 | 138 | circledat_EggerEST <- circle.radial(c(0,r_object$coef[1,1]),R.Egger,100,atan(Egger_circlemin),atan(Egger_circlemax)) 139 | cxEgger<-circledat_EggerEST$x 140 | cyEgger<-circledat_EggerEST$y 141 | 142 | ay <- list( 143 | zeroline = FALSE, 144 | showline = FALSE, 145 | mirror = "ticks", 146 | gridcolor = toRGB("white"), 147 | gridwidth = 0, 148 | zerolinecolor = toRGB("black"), 149 | zerolinewidth = 1, 150 | linecolor = toRGB("white"), 151 | linewidth = 0, 152 | title = "Beta*sqrt(Wj)" 153 | ) 154 | 155 | ax <- list( 156 | zeroline = TRUE, 157 | showline = FALSE, 158 | mirror = "ticks", 159 | gridcolor = toRGB("white"), 160 | gridwidth = 0, 161 | zerolinecolor = toRGB("black"), 162 | zerolinewidth = 1, 163 | linecolor = toRGB("white"), 164 | linewidth = 0, 165 | title= "sqrt(Wj)" 166 | ) 167 | 168 | if(nrow(r_object$data[r_object$data$Outliers=="Outlier",]) == 0){ 169 | 170 | T_PLOT<- plot_ly(r_object$data, mode="marker", type = 'scatter') %>% 171 | add_trace(x = r_object$data[r_object$data$Outliers=="Variant",]$Wj , y = r_object$data[r_object$data$Outliers=="Variant",]$BetaWj, name = 'Variant', mode = 'markers', marker= list(color="black"),text= r_object$data[r_object$data$Outliers=="Variant",]$SNP, hoverinfo = 'text') %>% 172 | add_trace(x = cxEgger , y = cyEgger, mode = 'line',showlegend=FALSE,name="Egger_CI", line= list(color = "#D55E00",size=1)) %>% 173 | layout(xaxis = ax,yaxis = ay) %>% 174 | add_segments(x = 0, xend = cos(atan(r_object$coef[2,1]))*R.Egger, y = r_object$coef[1,1], yend = (sin(atan(r_object$coef[2,1]))*R.Egger)+r_object$coef[1,1],name = "Egger", line= list(color = "#D55E00",size=1))%>% 175 | add_annotations(x = c(cxEgger[1],cos(atan(r_object$coef[2,1]))*R.Egger,cxEgger[100]), 176 | y = c(cyEgger[1],(sin(atan(r_object$coef[2,1]))*R.Egger)+r_object$coef[1,1],cyEgger[100]), 177 | text = c(round(r_object$confint[1],digits=3),round(r_object$coef[2,1],digits=3),round(r_object$confint[2],digits=3)), 178 | xref = "x", 179 | yref = "y", 180 | showarrow = TRUE, 181 | arrowhead = 0, 182 | arrowsize = 0, 183 | ax = 25, 184 | ay = 1) 185 | 186 | } 187 | 188 | if(nrow(r_object$data[r_object$data$Outliers=="Outlier",]) > 0){ 189 | 190 | T_PLOT<- plot_ly(r_object$data, mode="marker", type = 'scatter') %>% 191 | add_trace(x = r_object$data[r_object$data$Outliers=="Variant",]$Wj , y = r_object$data[r_object$data$Outliers=="Variant",]$BetaWj, name = 'Variant', mode = 'markers', marker= list(color="black"),text= r_object$data[r_object$data$Outliers=="Variant",]$SNP, hoverinfo = 'text') %>% 192 | add_trace(x = r_object$data[r_object$data$Outliers=="Outlier",]$Wj , y = r_object$data[r_object$data$Outliers=="Outlier",]$BetaWj, name = 'Outlier', mode = 'markers', marker= list(color="#E69F00"),text= r_object$data[r_object$data$Outliers=="Outlier",]$SNP, hoverinfo = 'text') %>% 193 | add_trace(x = cxEgger , y = cyEgger, mode = 'line',showlegend=FALSE,name="Egger_CI", line= list(color = "#D55E00",size=1)) %>% 194 | layout(xaxis = ax,yaxis = ay) %>% 195 | add_segments(x = 0, xend = cos(atan(r_object$coef[2,1]))*R.Egger, y = r_object$coef[1,1], yend = (sin(atan(r_object$coef[2,1]))*R.Egger)+r_object$coef[1,1],name = "Egger", line= list(color = "#D55E00",size=1))%>% 196 | add_annotations(x = c(cxEgger[1],cos(atan(r_object$coef[2,1]))*R.Egger,cxEgger[100]), 197 | y = c(cyEgger[1],(sin(atan(r_object$coef[2,1]))*R.Egger)+r_object$coef[1,1],cyEgger[100]), 198 | text = c(round(r_object$confint[1],digits=3),round(r_object$coef[2,1],digits=3),round(r_object$confint[2],digits=3)), 199 | xref = "x", 200 | yref = "y", 201 | showarrow = TRUE, 202 | arrowhead = 0, 203 | arrowsize = 0, 204 | ax = 25, 205 | ay = 1) 206 | 207 | } 208 | 209 | } 210 | 211 | if(TEST==FALSE){ 212 | T_PLOT<- as.character("Coming soon") 213 | 214 | } 215 | 216 | } 217 | 218 | return(T_PLOT) 219 | 220 | } 221 | -------------------------------------------------------------------------------- /R/rawdat_mvmr.R: -------------------------------------------------------------------------------- 1 | #' Raw multivariable MR summary data using lipid fractions as exposures and systolic blood pressure as an outcome. 2 | #' 3 | #' A dataset containing summary data on 145 genetic variants associated with either 4 | #' low-density lipoprotein (LDL), high-density lipoprotein (HDL), or triglycerides. Data includes variant rsid numbers, 5 | #' associations with each lipid fraction, the associations between genetic variants and systolic blood pressure, 6 | #' and corresponding standard errors. 7 | #' 8 | #' rawdat_mvmr 9 | #' 10 | #' @format A data frame with 145 rows and 9 variables. A full description of the data is available 11 | #' by using the command \code{vignette("MVMR")}. 12 | #' 13 | #' @source 14 | #' \itemize{ 15 | #' \item \url{http://www.mrbase.org/} 16 | #' \item \url{https://www.nature.com/articles/ng.2797} 17 | #' \item \url{https://www.nature.com/articles/ng.3768} 18 | #' } 19 | 20 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 21 | 22 | "rawdat_mvmr" -------------------------------------------------------------------------------- /R/snpcov_mvmr.R: -------------------------------------------------------------------------------- 1 | #' snpcov_mvmr 2 | #' 3 | #' Uses individual level genetic and exposure data to generate covariance matrices for estimated effects of individual genetic 4 | #' variants on each exposure. The function returns a number of covariance matrices equal to the number of SNPs, where SNP and 5 | #' row numbers reference ordered exposures. 6 | #' 7 | #' @param Gs A matrix or dataframe containing genetic instrument measures. Columns should indicate genetic variant number, with rows representing an observed measure of the genetic variant. 8 | #' @param Xs A matrix or dataframe containing exposure measures. Columns should indicate exposure number, with rows representing an observed measure for the given exposure. 9 | #' 10 | #' @return A list of covariance matrices with respect to each genetic variant, retaining the ordering in \code{Gs} 11 | #' 12 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 13 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 14 | #'@export 15 | #'@examples 16 | #' 17 | #' snpcov_mvmr(data[,1:10],data[,11:13]) 18 | #' 19 | 20 | snpcov_mvmr<-function(Gs,Xs){ 21 | 22 | betas<-matrix(0,ncol=length(Xs[1,]),nrow=length(Gs[1,])) 23 | 24 | resmat<-data.frame(rep(0,length(Gs[,1]))) 25 | 26 | for(j in 1:length(Xs[1,])){ 27 | 28 | for(i in 1:length(Gs[1,])){ 29 | 30 | betas[i,j]<-lm(Xs[,j]~-1 + Gs[,i])$coefficients 31 | 32 | resids<-data.frame(lm(Xs[,j]~-1 + Gs[,i])$residuals) 33 | 34 | resmat<-cbind(resmat,resids) 35 | 36 | } 37 | 38 | } 39 | 40 | resmat<-resmat[,-1] 41 | 42 | sigmalist <- vector("list", length(Gs[1,])) 43 | 44 | for(i in 1:length(Gs[1,])){ 45 | 46 | sigma_mattemp<-matrix(((t(Gs[,i]) %*% Gs[,i])^-1)/length(Gs[,i]),ncol=length(Xs[1,]) 47 | ,nrow=length(Xs[1,])) 48 | 49 | for(j in 1:length(Xs[1,])){ 50 | 51 | for(k in 1:length(Xs[1,])){ 52 | 53 | sigma_mattemp[k,j]<-sigma_mattemp[k,j] * sum(resmat[,i+((k-1)*length(Gs))] * resmat[,i+((j-1)*length(Gs))]) 54 | 55 | 56 | } 57 | } 58 | 59 | sigmalist[[i]] <-sigma_mattemp 60 | 61 | } 62 | 63 | return(sigmalist) 64 | 65 | } -------------------------------------------------------------------------------- /R/strength_mvmr.R: -------------------------------------------------------------------------------- 1 | #' strength_mvmr 2 | #' 3 | #' Calculates the conditional F-statistic for assessing instrument strength in two sample summary multivariable Mendelian randomization. 4 | #' The function takes a formatted dataframe as an input, obtained using the function \code{format_mvmr}. Additionally, covariance matrices 5 | #' for estimated effects of individual genetic variants on each exposure can also be provided. These can be estimated using external data by 6 | #' applying the \code{snpcov_mvmr} or \code{phenocov_mvmr} functions, are input manually. The function returns a dataframe including the conditional 7 | #' F-statistic with respect to each exposure. A conventional F-statistic threshold of 10 is used in basic assessments of instrument strength. 8 | #' 9 | #' 10 | #' @param r_input r_input A formatted data frame using the \code{format_mvmr} function. 11 | #' @param gencov Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default. 12 | #' 13 | #' @return A dataframe showing the conditional F-statistic for each exposure. 14 | #' 15 | #'@author Wes Spiller; Eleanor Sanderson; Jack Bowden. 16 | #'@references Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 17 | #'@export 18 | #'@examples 19 | #' 20 | #' strength_mvmr(data,covariances) 21 | #' 22 | 23 | strength_mvmr<-function(r_input,gencov){ 24 | 25 | #gencov is the covariance between the effect of the genetic variants on each exposure. 26 | #By default it is set to 0. 27 | 28 | if(missing(gencov)) { 29 | gencov<-as.numeric(0) 30 | warning("Covariance between effect of genetic variants on each exposure not specified. Fixing covariance at 0.") 31 | } 32 | 33 | 34 | # Inverse variance weighting is used. 35 | 36 | Wj<-1/r_input[,3]^2 37 | 38 | #Determine the number of exposures included in the model 39 | 40 | exp.number<-length(names(r_input)[-c(1,2,3)])/2 41 | 42 | A<-summary(lm(as.formula(paste("betaYG~ -1 +", paste(names(r_input)[ 43 | seq(4,3+exp.number,by=1)], collapse="+"))) 44 | ,weights=Wj,data=r_input))$coef 45 | 46 | #Rename the regressors for ease of interpretation 47 | for(i in 1:exp.number){ 48 | dimnames(A)[[1]][i]<- paste0("exposure",i,collapse="") 49 | } 50 | 51 | ############################################# 52 | # Generalised instrument strength het.stats # 53 | ############################################# 54 | 55 | #Create an empty matrix for delta value (coefficients regressing each set of exposure effects upon other 56 | #exposure effects) 57 | 58 | delta_mat<-matrix(0,ncol=exp.number,nrow=exp.number-1) 59 | 60 | #Obtain delta values fitting regression models for each set of exposure effects upon other exposure effects 61 | for(i in 1:exp.number){ 62 | regressand<-names(r_input[3 + i]) 63 | regressors<-names(r_input)[-c(1,2,3, 64 | 4+exp.number:length(names(r_input)))] 65 | C<-paste(regressand, "~", "-1 +", paste(regressors[-i], collapse="+")) 66 | D.reg<-lm(C,data=r_input) 67 | delta_mat[,i]<-D.reg$coefficients 68 | } 69 | 70 | sigma2xj_dat<-matrix(ncol=exp.number,nrow=length(r_input[,1]),0) 71 | 72 | if(length(gencov) > 0){ 73 | 74 | #Create a subset containing only standard errors for exposure effect estimates 75 | sebetas<-r_input[,(exp.number + 4):length(r_input)] 76 | 77 | #Generates the sigma2xj values for each exposure 78 | for(i in 1:exp.number){ 79 | se.temp<-as.matrix(sebetas[,-i]) 80 | for(j in 1:(exp.number-1)){ 81 | sigma2xj_dat[,i]<- sigma2xj_dat[,i] + (se.temp[,j]^2 * delta_mat[j,i]^2) 82 | } 83 | sigma2xj_dat[,i]<- sigma2xj_dat[,i] + sebetas[,i]^2 84 | 85 | } 86 | 87 | 88 | } 89 | 90 | if(length(gencov) > 2){ 91 | 92 | #Create a subset containing only standard errors for exposure effect estimates 93 | sebetas<-r_input[,(exp.number + 4):length(r_input)] 94 | 95 | #Generates the sigma2xj values for each exposure 96 | for(i in 1:exp.number){ 97 | se.temp<-as.matrix(sebetas[,-i]) 98 | for(j in 1:(exp.number-1)){ 99 | sigma2xj_dat[,i]<- sigma2xj_dat[,i] + (se.temp[,j]^2 * delta_mat[j,i]^2) 100 | } 101 | sigma2xj_dat[,i]<- sigma2xj_dat[,i] + sebetas[,i]^2 - 0 102 | 103 | for(k in 1:(exp.number-1)){ 104 | 105 | temp<-seq(1:exp.number) 106 | 107 | temp<-temp[-i] 108 | 109 | for(l in 1:length(r_input[,1])){ 110 | 111 | sigma2xj_dat[l,i]<- sigma2xj_dat[l,i] - delta_mat[j,i]*2*gencov[[l]][i,temp[k]] 112 | 113 | } 114 | 115 | } 116 | 117 | } 118 | 119 | } 120 | 121 | 122 | #Create an empty matrix for instrument strength Q statistics 123 | Q_strength<-matrix(ncol=exp.number,nrow=1,0) 124 | 125 | #Generates the component of the Q statistic to be subtracted from the exposure estimates 126 | for(i in 1:exp.number){ 127 | betas<-r_input[,c(4:(3+exp.number))] 128 | betas<-data.frame(betas[,-i]) 129 | temp.sub <- 0 130 | for(j in 1:(exp.number-1)){ 131 | temp.sub<-temp.sub + (delta_mat[j,i] * betas[,j]) 132 | } 133 | 134 | #Populates matrix of Q statistics with respect to instrument strength 135 | Q_strength[i]<- sum( (1/sigma2xj_dat[,i]) * ((r_input[,3+i] - temp.sub)^2) ) 136 | Q_strength[i]<-Q_strength[i]/nrow(r_input) 137 | 138 | } 139 | 140 | Q_strength<-data.frame(Q_strength) 141 | names(Q_strength)<-dimnames(A)[[1]] 142 | rownames(Q_strength)<-"F-statistic" 143 | 144 | 145 | ########## 146 | # Output # 147 | ########## 148 | 149 | # Print a few summary elements that are common to both lm and plm model summary objects 150 | cat("\n") 151 | 152 | cat("Conditional F-statistics for instrument strength\n") 153 | 154 | cat("\n") 155 | 156 | print(Q_strength) 157 | 158 | return(Q_strength) 159 | 160 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MRPracticals 2 | 3 | The `MRPracticals` R package provides necessary information for MR course practical sessions. It requires R version 3.5 and R Studio to be installed, as well 4 | as Rtools which is available at https://cran.r-project.org/bin/windows/Rtools/ 5 | for processing vignette files. It is also necessary to have a google account for MR Base authorisation. 6 | 7 | Information for two separate pratical sessions is currently included, pertaining to: 8 | 9 | 1. MR Base 10 | 2. The RadialMR package 11 | 3. The MVMR package 12 | 13 | ## Installation 14 | 15 | To install `MRPracticals` directly from the GitHub repository, first make sure you have R version 3.5 or higher, R Studio, and R Tools version 3.5 installed. 16 | 17 | Next, open R Studio and install the `devtools`, `knitr`, and `rmarkdown` packages: 18 | 19 | install.packages(c("devtools", "knitr", "rmarkdown")) 20 | 21 | Next, we need to install the `TwoSampleMR` and `MRInstruments` R packages from Github. 22 | 23 | library(devtools) 24 | install_github(c("MRCIEU/TwoSampleMR","MRCIEU/MRInstruments")) 25 | 26 | Then the `MRPracticals` package can be installed using: 27 | 28 | library(devtools) 29 | install_github("WSpiller/MRPracticals",build_opts = c("--no-resave-data", "--no-manual"),build_vignettes = TRUE) 30 | 31 | To update the package just run the `install_github("WSpiller/MRPracticals", build_opts = c("--no-resave-data", "--no-manual"))` command again. 32 | 33 | ## Description 34 | 35 | The `MRPracticals` package contains a sample data frame, and two vignette files with code and instructions: 36 | 37 | 1. Running the command `vignette("MRBase")` will display a document giving a detailed description of the MR Base practical. 38 | 39 | 2. Running the command `vignette("RadialMR")` will display a document giving a detailed description of the RadialMR practical. 40 | 41 | 3. Running the command `vignette("MVMR Tutorial")` will display a document giving a detailed description of the MVMR practical. 42 | 43 | ## Acknowledgments 44 | 45 | This package contains material from the MR course, conducted at the University of Bristol. 46 | 47 | ## License 48 | 49 | This project is licensed under GNU GPL v2. 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /data/BMIdat.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/data/BMIdat.RData -------------------------------------------------------------------------------- /data/rawdat_mvmr.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/data/rawdat_mvmr.RData -------------------------------------------------------------------------------- /man/BMIdat.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/BMIdat.R 3 | \docType{data} 4 | \name{BMIdat} 5 | \alias{BMIdat} 6 | \title{Example Two-Sample Summary Data for use in MR Practicals.} 7 | \format{ 8 | A data frame with 62 rows and 43 variables, created using code presented in \code{vignette("MRBase")}. 9 | } 10 | \source{ 11 | \itemize{ 12 | \item \url{https://www.nature.com/articles/nature14177} 13 | \item \url{http://www.nealelab.is/blog/2017/9/11/details-and-considerations-of-the-uk-biobank-gwas} 14 | } 15 | } 16 | \usage{ 17 | BMIdat 18 | } 19 | \description{ 20 | A dataset containing summary data for 62 independent SNPs associated with body mass index from Locke (2015), and summary estimates for their corresponding 21 | association with systolic blood pressure from the UK Biobank. 22 | } 23 | \details{ 24 | BMIdat. 25 | } 26 | \author{ 27 | Wes Spiller; Jack Bowden 28 | } 29 | \keyword{datasets} 30 | -------------------------------------------------------------------------------- /man/egger_radial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/egger_radial.R 3 | \name{egger_radial} 4 | \alias{egger_radial} 5 | \title{egger_radial} 6 | \usage{ 7 | egger_radial(r_input, alpha, weights, summary) 8 | } 9 | \arguments{ 10 | \item{r_input}{A formatted data frame using the \code{format_radial} function.} 11 | 12 | \item{alpha}{A value specifying the statistical significance threshold for identifying outliers (\code{0.05} specifies a p-value threshold of 0.05).} 13 | 14 | \item{weights}{A value specifying the inverse variance weights used to calculate the MR-Egger estimate and Rucker's Q statistic. By default modified second order weights are used, but one can choose to select first order (\code{1}), second order (\code{2}) or modified second order weights (\code{3}).} 15 | 16 | \item{summary}{Indicates whether a summary of the radial MR-Egger model should be printed (default= \code{TRUE}) or withheld (\code{FALSE}).} 17 | } 18 | \value{ 19 | An object of class \code{"egger"} containing the following components:\describe{ 20 | \item{\code{coef}}{A matrix giving the intercept and slope coefficient, corresponding standard errors, t-statistics, and (two-sided) p-values.} 21 | \item{\code{qstatistic}}{Rucker's Q statistic for overall heterogeneity.} 22 | \item{\code{df}}{Degrees of freedom. This is equal to the number of variants -2 when fitting the radial MR-Egger model.} 23 | \item{\code{outliers}}{A data frame containing variants identified as outliers, with respective Q statistics, chi-squared tests and SNP identification.} 24 | \item{\code{data}}{A data frame containing containing SNP IDs, inverse variance weights, the product of the inverse variance weight and ratio estimate for each variant, contribution to overall heterogeneity with corresponding p-value, and a factor indicator showing outlier status.} 25 | \item{\code{confint}}{A vector giving lower and upper confidence limits for the radial MR-Egger effect estimate.} 26 | } 27 | } 28 | \description{ 29 | Fits a radial MR-Egger model using first order, second order, or modified second order weights. Outliers are identified using a significance threshold specified by the user. The function returns an object of class \code{"egger"}, containing regression estimates, a measure of total heterogeneity using Rucker's Q statistic, the individual contribution to overall heterogeneity of each variant, and a data frame for use in constructing the radial plot. 30 | } 31 | \examples{ 32 | 33 | egger_radial(r_input,0.05,1) 34 | 35 | } 36 | \references{ 37 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 38 | } 39 | \author{ 40 | Wes Spiller; Jack Bowden. 41 | } 42 | -------------------------------------------------------------------------------- /man/format_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/format_function.R 3 | \name{format_mvmr} 4 | \alias{format_mvmr} 5 | \title{format_mvmr} 6 | \usage{ 7 | format_mvmr(BXGs, BYG, seBXGs, seBYG, RSID) 8 | } 9 | \arguments{ 10 | \item{BXGs}{A matrix containing beta-coefficient values for genetic associations with the each exposure. Columns should indicate exposure number, with rows representing estimates for a given genetic variant.} 11 | 12 | \item{BYG}{A numeric vector of beta-coefficient values for genetic associations with the outcome.} 13 | 14 | \item{seBXGs}{A matrix containing standard errors corresponding to the matrix of beta-coefficients \code{BXGs}.} 15 | 16 | \item{seBYG}{A numeric vector of standard errors corresponding to the beta-coefficients \code{BYG}.} 17 | 18 | \item{RSID}{A vector of names for genetic variants included in the analysis. If variant IDs are not provided (\code{RSID="NULL"}), a vector of ID numbers will be generated.} 19 | } 20 | \value{ 21 | A formatted data frame. 22 | } 23 | \description{ 24 | Reads in summary data. Checks and organises columns for use in calculating multivariable Mendelian Randomization analyses. Where variant IDs are not provided, a vector is generated for variant identification. 25 | } 26 | \examples{ 27 | 28 | format_mvmr(summarydata[,c(1,2)],summarydata[,5],summarydata[,c(3,4)],summarydata[,6]) 29 | 30 | } 31 | \references{ 32 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 33 | } 34 | \author{ 35 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 36 | } 37 | -------------------------------------------------------------------------------- /man/format_radial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/format_radial.R 3 | \name{format_radial} 4 | \alias{format_radial} 5 | \title{format_radial} 6 | \usage{ 7 | format_radial(BXG, BYG, seBXG, seBYG, RSID) 8 | } 9 | \arguments{ 10 | \item{BXG}{A numeric vector of beta-coefficient values for genetic associations with the first variable (exposure).} 11 | 12 | \item{BYG}{A numeric vector of beta-coefficient values for genetic associations with the second variable (outcome).} 13 | 14 | \item{seBXG}{The standard errors corresponding to the beta-coefficients \code{BXG}.} 15 | 16 | \item{seBYG}{The standard errors corresponding to the beta-coefficients \code{BYG}.} 17 | 18 | \item{RSID}{A vector of names for genetic variants included in the analysis. If variant IDs are not provided (\code{RSID="NULL"}), a vector of ID numbers will be generated.} 19 | } 20 | \value{ 21 | A formatted data frame. 22 | } 23 | \description{ 24 | Reads in summary data. Checks and organises columns for use in calculating radial IVW and radial MR-Egger estimates. Where variant IDs are not provided, a vector is generated for variant identification. 25 | } 26 | \examples{ 27 | 28 | format_radial(summarydata[,1],summarydata[,3],summarydata[,2],summarydata[,4]) 29 | 30 | } 31 | \references{ 32 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 33 | } 34 | \author{ 35 | Wes Spiller; Jack Bowden. 36 | } 37 | -------------------------------------------------------------------------------- /man/funnel_radial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/funnel_radial.R 3 | \name{funnel_radial} 4 | \alias{funnel_radial} 5 | \title{funnel_radial} 6 | \usage{ 7 | funnel_radial(r_object, show_transform) 8 | } 9 | \arguments{ 10 | \item{r_object}{An object of class \code{"IVW"} or \code{"egger"}. For visualising both estimates simultaneously, both objects should be included as a vector c(\code{A},\code{B}), where \code{A} and \code{B} denote the \code{"IVW"} and \code{"egger"} objects respectively.} 11 | 12 | \item{show_transform}{Indicates whether to produce a plot including lines showing the magnitude of the MR Egger transformation for each variant (\code{TRUE}), or a scatterplot showing only the variants and corresponding estimates (\code{FALSE}).} 13 | } 14 | \value{ 15 | A ggplot object containing a radial funnel plot of either the IVW, MR-Egger, or both estimates simultaneously. 16 | } 17 | \description{ 18 | A function for producing generalized radial IVW and MR-Egger funnel plots either individually or simultaneously. The function also allows for lines indicating the magnitude for the MR Egger transformation for each variant, though it should be noted that this distance is a function of the weight attributed to the variant, and is therefore not indicative of outliers. 19 | } 20 | \examples{ 21 | 22 | funnel_radial(r_object,TRUE) 23 | } 24 | \references{ 25 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 26 | } 27 | \author{ 28 | Wes Spiller; Jack Bowden. 29 | } 30 | -------------------------------------------------------------------------------- /man/ivw_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ivw_mvmr.R 3 | \name{ivw_mvmr} 4 | \alias{ivw_mvmr} 5 | \title{ivw_mvmr} 6 | \usage{ 7 | ivw_mvmr(r_input, gencov) 8 | } 9 | \arguments{ 10 | \item{r_input}{A formatted data frame using the \code{format_mvmr} function.} 11 | 12 | \item{gencov}{Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default.} 13 | } 14 | \value{ 15 | An dataframe containing MVMR results, including estimated coefficients, their standard errors, t-statistics, and corresponding (two-sided) p-values. 16 | } 17 | \description{ 18 | Fits an IVW multivariable Mendelian randomization model using first order weights. 19 | } 20 | \examples{ 21 | 22 | ivw_mvmr(r_input) 23 | 24 | } 25 | \references{ 26 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 27 | } 28 | \author{ 29 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 30 | } 31 | -------------------------------------------------------------------------------- /man/ivw_radial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ivw_radial.R 3 | \name{ivw_radial} 4 | \alias{ivw_radial} 5 | \title{ivw_radial} 6 | \usage{ 7 | ivw_radial(r_input, alpha, weights, tol) 8 | } 9 | \arguments{ 10 | \item{r_input}{A formatted data frame using the \code{format_radial} function.} 11 | 12 | \item{alpha}{A value specifying the statistical significance threshold for identifying outliers (\code{0.05} specifies a p-value threshold of 0.05).} 13 | 14 | \item{weights}{A value specifying the inverse variance weights used to calculate IVW estimate and Cochran's Q statistic. By default modified second order weights are used, but one can choose to select first order (\code{1}), second order (\code{2}) or modified second order weights (\code{3}).} 15 | 16 | \item{tol}{A value indicating the tolerance threshold for performing the iterative IVW approach. The value represents the minimum difference between the coefficients of the previous and current iterations required for a further iteration to be performed (default= \code{0.0001}).} 17 | } 18 | \value{ 19 | An object of class \code{"IVW"} containing the following components:\describe{ 20 | \item{\code{coef}}{The estimated coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 21 | \item{\code{qstatistic}}{Cochran's Q statistic for overall heterogeneity.} 22 | \item{\code{df}}{Degrees of freedom. This is equal to the number of variants -1 when fitting the radial IVW model.} 23 | \item{\code{outliers}}{A data frame containing variants identified as outliers, with respective Q statistics, chi-squared tests and SNP identification.} 24 | \item{\code{data}}{A data frame containing containing SNP IDs, inverse variance weights, the product of the inverse variance weight and ratio estimate for each variant, contribution to overall heterogeneity with corresponding p-value, and a factor indicator showing outlier status.} 25 | \item{\code{confint}}{A vector giving lower and upper confidence limits for the radial IVW effect estimate.} 26 | \item{\code{it.coef}}{The estimated iterative coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 27 | \item{\code{it.confint}}{A vector giving lower and upper confidence limits for the iterative radial IVW effect estimate.} 28 | \item{\code{fe.coef}}{The estimated fixed effect exact coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 29 | \item{\code{fe.confint}}{A vector giving lower and upper confidence limits for the fixed effect exact radial IVW effect estimate.} 30 | \item{\code{re.coef}}{The estimated random effect exact coefficient, its standard error, t-statistic and corresponding (two-sided) p-value.} 31 | \item{\code{re.confint}}{A vector giving lower and upper confidence limits for the random effect exact radial IVW effect estimate.} 32 | \item{\code{mf}}{The mean F statistic for the set of genetic variants, indicative of instrument strength.} 33 | 34 | } 35 | } 36 | \description{ 37 | Fits a radial inverse variance weighted (IVW) model using first order, second order, or modified second order weights. Outliers are identified using a significance threshold specified by the user. The function returns an object of class \code{"IVW"}, containing regression estimates, a measure of total heterogeneity using Cochran's Q statistic, the individual contribution to overall heterogeneity of each variant, and a data frame for use in constructing the radial plot. 38 | } 39 | \examples{ 40 | 41 | ivw_radial(r_input,0.05,1,0.0001,T) 42 | 43 | } 44 | \references{ 45 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 46 | } 47 | \author{ 48 | Wes Spiller; Jack Bowden. 49 | } 50 | -------------------------------------------------------------------------------- /man/mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/mvmr.R 3 | \name{mvmr} 4 | \alias{mvmr} 5 | \title{mvmr (legacy)} 6 | \usage{ 7 | mvmr(r_input, gencov, weights) 8 | } 9 | \arguments{ 10 | \item{r_input}{A formatted data frame using the \code{format_mvmr} function.} 11 | 12 | \item{gencov}{Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default.} 13 | 14 | \item{weights}{A value specifying the inverse variance weights used to calculate IVW estimate and Cochran's Q statistic. Currently only first order weights are available (\code{1}).} 15 | } 16 | \value{ 17 | An object of class \code{"MVMRIVW"} containing the following components:\describe{ 18 | \item{\code{summary}}{A summary of the MVMR regression model, including estimated coefficients, standard errors, t-statistics, p-values, and heterogeneity statistics.} 19 | \item{\code{coef}}{The estimated coefficients, their standard errors, t-statistics, and corresponding (two-sided) p-values.} 20 | \item{\code{Q_strength}}{A data frame displaying modified Cochran's Q statistics for assessing instrument strength with respect to each exposure. The Q-statistic increases proportionally with instrument strength, and analogous to univariate MR analyses, a value equal to or greater than 10 can be used as a minimum threshold for instrument strength. Note that for these statistics it is not informative to evaluate p-values.} 21 | \item{\code{Q_valid}}{A modified form of Cochran's Q statistic measuring heterogeneity in causal effect estimates obtained using each genetic variant. Observed heterogeneity is indicative of a violation of the exclusion restriction assumption in MR (validity), which can result in biased effect estimates.} 22 | \item{\code{p_valid}}{A p-value corresponding to the heterogeneity measure for instrument validity (\code{Q_valid})} 23 | } 24 | } 25 | \description{ 26 | Note: This function is from the old version of the MVMR package and will be replaced in the future: The gencov argument should be set to zero when using \code{mvmr()}. 27 | } 28 | \details{ 29 | Fits an IVW multivariable Mendelian randomization model using first order weights. The function returns an object of class \code{"MVMRIVW"}, containing regression estimates, estimated heterogeneity as a measure of instrument strength (\code{Q_strength}), and estimated heterogeneity as a measure of instrument validity (\code{Q_valid}). 30 | } 31 | \examples{ 32 | 33 | mvmr(r_input,0,1) 34 | 35 | } 36 | \references{ 37 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 38 | } 39 | \author{ 40 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 41 | } 42 | -------------------------------------------------------------------------------- /man/phenocov_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/phenocov_mvmr.R 3 | \name{phenocov_mvmr} 4 | \alias{phenocov_mvmr} 5 | \title{phenocov_mvmr} 6 | \usage{ 7 | phenocov_mvmr(Pcov, seBXGs) 8 | } 9 | \arguments{ 10 | \item{Pcov}{A phenotypic matrix using exposures, constructed using individual level exposure data. Columns should be ordered by exposure so as to match \code{format_mvmr}.} 11 | 12 | \item{seBXGs}{A matrix containing standard errors corresponding in relation to the gene-exposure association for each SNP.} 13 | } 14 | \value{ 15 | A list of covariance matrices with respect to each genetic variant, retaining the ordering in \code{Gs} 16 | } 17 | \description{ 18 | Uses an external phenotypic covariance matrix and summary data to estimate covariance matrices for estimated effects of individual genetic 19 | variants on each exposure. The function returns a number of covariance matrices equal to the number of SNPs, where SNP and 20 | row numbers reference ordered exposures. 21 | } 22 | \examples{ 23 | 24 | phenocov_mvmr(Pcov,summarydata[,c(3,4)]) 25 | 26 | } 27 | \references{ 28 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 29 | } 30 | \author{ 31 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 32 | } 33 | -------------------------------------------------------------------------------- /man/pleiotropy_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pleiotropy_mvmr.R 3 | \name{pleiotropy_mvmr} 4 | \alias{pleiotropy_mvmr} 5 | \title{pleiotropy_mvmr} 6 | \usage{ 7 | pleiotropy_mvmr(r_input, gencov) 8 | } 9 | \arguments{ 10 | \item{r_input}{r_input A formatted data frame using the \code{format_mvmr} function.} 11 | 12 | \item{gencov}{Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default.} 13 | } 14 | \value{ 15 | A Q-statistic for instrument validity and the corresponding p-value 16 | } 17 | \description{ 18 | Calculates modified form of Cochran's Q statistic measuring heterogeneity in causal effect estimates obtained using each genetic variant. Observed heterogeneity is indicative of a violation of the exclusion restriction assumption in MR (validity), which can result in biased effect estimates. 19 | The function takes a formatted dataframe as an input, obtained using the function \code{format_mvmr}. Additionally, covariance matrices 20 | for estimated effects of individual genetic variants on each exposure can also be provided. These can be estimated using external data by 21 | applying the \code{snpcov_mvmr} or \code{phenocov_mvmr} functions, are input manually. The function returns a dataframe including the conditional 22 | Q-statistic for instrument validity, and a corresponding P-value. 23 | } 24 | \examples{ 25 | 26 | pleiotropy_mvmr(data,covariances) 27 | 28 | } 29 | \references{ 30 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 31 | } 32 | \author{ 33 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 34 | } 35 | -------------------------------------------------------------------------------- /man/plot_radial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plot_radial.R 3 | \name{plot_radial} 4 | \alias{plot_radial} 5 | \title{plot_radial} 6 | \usage{ 7 | plot_radial(r_object, radial_scale, show_outliers, scale_match) 8 | } 9 | \arguments{ 10 | \item{r_object}{An object of class \code{"IVW"} or \code{"egger"}. For visualising both estimates simultaneously, both objects should be included as a vector c(\code{A},\code{B}), where \code{A} and \code{B} denote the \code{"IVW"} and \code{"egger"} objects respectively.} 11 | 12 | \item{radial_scale}{Indicates whether to produce a plot including a full radial scale (\code{TRUE}), or a scatterplot showing only the effect estimates (\code{FALSE}).} 13 | 14 | \item{show_outliers}{Indicates whether display only the set of variants identified as outliers (\code{TRUE}) or the complete set of variants (\code{FALSE}). Note that when (\code{show_outliers=TRUE}), non-outlying variants further from the origin than the furthest outlier will cause an error message that one or more points have been omitted. These are non-outlying variants beyond the scale. If no outliers are present, a plot will be produced using the full set of variants, with an accompanying message indicating the absence of outliers.} 15 | 16 | \item{scale_match}{Indicates whether x and y axes should have the same range(\code{TRUE}), or different ranges (\code{FALSE}) This improves the interpretation of the radial scale, and is set to \code{FALSE} when the radial scale is omitted from the plot.} 17 | } 18 | \value{ 19 | A ggplot object containing a radial plot of either the IVW, MR-Egger, or both estimates simultaneously. 20 | } 21 | \description{ 22 | A function for producing radial IVW and MR-Egger plots either individually or simultaneously. The function allows for a variety of aesthetic and scaling options, utilising the output from the \code{IVW_radial} and \code{egger_radial} functions. 23 | } 24 | \examples{ 25 | 26 | plot_radial(r_object,TRUE,TRUE,TRUE) 27 | 28 | plot_radial(c(r_object,r_object),TRUE,TRUE,FALSE) 29 | } 30 | \references{ 31 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 32 | } 33 | \author{ 34 | Wes Spiller; Jack Bowden. 35 | } 36 | -------------------------------------------------------------------------------- /man/plotly_radial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/plotly_radial.R 3 | \name{plotly_radial} 4 | \alias{plotly_radial} 5 | \title{plotly_radial} 6 | \usage{ 7 | plotly_radial(r_object, TEST) 8 | } 9 | \arguments{ 10 | \item{r_object}{An object of class \code{"IVW"} or \code{"egger"}.} 11 | } 12 | \value{ 13 | A plotly object containing a radial plot of either the IVW or MR-Egger estimates. Hovering the mouse over individual datapoints will highlight the corresponding SNP identification number for that observation. 14 | } 15 | \description{ 16 | A function for producing interactive radial IVW and MR-Egger plots individually.The function utilises the output from the \code{IVW_radial} and \code{egger_radial} functions. 17 | } 18 | \examples{ 19 | 20 | plotly_radial(r_object) 21 | } 22 | \references{ 23 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 24 | } 25 | \author{ 26 | Wes Spiller; Jack Bowden. 27 | } 28 | -------------------------------------------------------------------------------- /man/rawdat_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rawdat_mvmr.R 3 | \docType{data} 4 | \name{rawdat_mvmr} 5 | \alias{rawdat_mvmr} 6 | \title{Raw multivariable MR summary data using lipid fractions as exposures and systolic blood pressure as an outcome.} 7 | \format{ 8 | A data frame with 145 rows and 9 variables. A full description of the data is available 9 | by using the command \code{vignette("MVMR")}. 10 | } 11 | \source{ 12 | \itemize{ 13 | \item \url{http://www.mrbase.org/} 14 | \item \url{https://www.nature.com/articles/ng.2797} 15 | \item \url{https://www.nature.com/articles/ng.3768} 16 | } 17 | } 18 | \usage{ 19 | rawdat_mvmr 20 | } 21 | \description{ 22 | A dataset containing summary data on 145 genetic variants associated with either 23 | low-density lipoprotein (LDL), high-density lipoprotein (HDL), or triglycerides. Data includes variant rsid numbers, 24 | associations with each lipid fraction, the associations between genetic variants and systolic blood pressure, 25 | and corresponding standard errors. 26 | } 27 | \details{ 28 | rawdat_mvmr 29 | } 30 | \author{ 31 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 32 | } 33 | \keyword{datasets} 34 | -------------------------------------------------------------------------------- /man/snpcov_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/snpcov_mvmr.R 3 | \name{snpcov_mvmr} 4 | \alias{snpcov_mvmr} 5 | \title{snpcov_mvmr} 6 | \usage{ 7 | snpcov_mvmr(Gs, Xs) 8 | } 9 | \arguments{ 10 | \item{Gs}{A matrix or dataframe containing genetic instrument measures. Columns should indicate genetic variant number, with rows representing an observed measure of the genetic variant.} 11 | 12 | \item{Xs}{A matrix or dataframe containing exposure measures. Columns should indicate exposure number, with rows representing an observed measure for the given exposure.} 13 | } 14 | \value{ 15 | A list of covariance matrices with respect to each genetic variant, retaining the ordering in \code{Gs} 16 | } 17 | \description{ 18 | Uses individual level genetic and exposure data to generate covariance matrices for estimated effects of individual genetic 19 | variants on each exposure. The function returns a number of covariance matrices equal to the number of SNPs, where SNP and 20 | row numbers reference ordered exposures. 21 | } 22 | \examples{ 23 | 24 | snpcov_mvmr(data[,1:10],data[,11:13]) 25 | 26 | } 27 | \references{ 28 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 29 | } 30 | \author{ 31 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 32 | } 33 | -------------------------------------------------------------------------------- /man/strength_mvmr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/strength_mvmr.R 3 | \name{strength_mvmr} 4 | \alias{strength_mvmr} 5 | \title{strength_mvmr} 6 | \usage{ 7 | strength_mvmr(r_input, gencov) 8 | } 9 | \arguments{ 10 | \item{r_input}{r_input A formatted data frame using the \code{format_mvmr} function.} 11 | 12 | \item{gencov}{Calculating heterogeneity statistics requires the covariance between the effect of the genetic variants on each exposure to be known. This can either be estimated from individual level data, be assumed to be zero, or fixed at zero using non-overlapping samples of each exposure GWAS. A value of \code{0} is used by default.} 13 | } 14 | \value{ 15 | A dataframe showing the conditional F-statistic for each exposure. 16 | } 17 | \description{ 18 | Calculates the conditional F-statistic for assessing instrument strength in two sample summary multivariable Mendelian randomization. 19 | The function takes a formatted dataframe as an input, obtained using the function \code{format_mvmr}. Additionally, covariance matrices 20 | for estimated effects of individual genetic variants on each exposure can also be provided. These can be estimated using external data by 21 | applying the \code{snpcov_mvmr} or \code{phenocov_mvmr} functions, are input manually. The function returns a dataframe including the conditional 22 | F-statistic with respect to each exposure. A conventional F-statistic threshold of 10 is used in basic assessments of instrument strength. 23 | } 24 | \examples{ 25 | 26 | strength_mvmr(data,covariances) 27 | 28 | } 29 | \references{ 30 | Sanderson, E., et al., An examination of multivariable Mendelian randomization in the single-sample and two-sample summary data settings. International Journal of Epidemiology, 2018. [Internet]. 2018;dyy262. Available from: https://dx.doi.org/10.1093/ije/dyy262 31 | } 32 | \author{ 33 | Wes Spiller; Eleanor Sanderson; Jack Bowden. 34 | } 35 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | mrbase.oauth 2 | -------------------------------------------------------------------------------- /vignettes/BMIdat.csv: -------------------------------------------------------------------------------- 1 | "id.expout","SNP","effect_allele.exposure","other_allele.exposure","effect_allele.outcome","other_allele.outcome","beta.exposure","beta.outcome","eaf.exposure","eaf.outcome","remove","palindromic","ambiguous","id.outcome","se.outcome","samplesize.outcome","ncase.outcome","ncontrol.outcome","pval.outcome","units.outcome","outcome","consortium.outcome","year.outcome","pmid.outcome","category.outcome","subcategory.outcome","originalname.outcome","outcome.deprecated","mr_keep.outcome","data_source.outcome","chr.exposure","gene.exposure","se.exposure","pval.exposure","units.exposure","exposure","mr_keep.exposure","pval_origin.exposure","units.exposure_dat","id.exposure","action","mr_keep","power" 2 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1000940","G","A","G","A",0.019,0.00065575,0.32,0.300732,FALSE,FALSE,FALSE,"UKB-a:360",0.00268698,317754,0,0,0.807195,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","17","RABEP1",0.00331632653061224,1e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 3 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs10132280","C","A","C","A",0.023,-0.00103509,0.682,0.698687,FALSE,FALSE,FALSE,"UKB-a:360",0.0026946,317754,0,0,0.70088,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","14","STXBP6",0.00357142857142857,1e-11,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 4 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1016287","C","T","C","T",-0.023,-0.0116373,0.713,0.70127,FALSE,FALSE,FALSE,"UKB-a:360",0.00269078,317754,0,0,1.52671e-05,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","2","FLJ30838",0.00357142857142857,2e-11,"kg/m2 increase","Body mass index",FALSE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 5 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs10182181","G","A","G","A",0.031,-0.0092675,0.462,0.486582,FALSE,FALSE,FALSE,"UKB-a:360",0.0024606,317754,0,0,0.000165674,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","2","ADCY3",0.00306122448979592,9e-24,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 6 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs10733682","A","G","A","G",0.017,0.00580081,0.478,0.472642,FALSE,FALSE,FALSE,"UKB-a:360",0.00249943,317754,0,0,0.0202954,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","9","LMX1B",0.00306122448979592,2e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 7 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs10938397","G","A","G","A",0.04,0.00430864,0.434,0.434075,FALSE,FALSE,FALSE,"UKB-a:360",0.00248746,317754,0,0,0.083249,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","4","GNPDA2",0.00306122448979592,3e-38,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 8 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs10968576","G","A","G","A",0.025,0.00896798,0.32,0.323134,FALSE,FALSE,FALSE,"UKB-a:360",0.0026254,317754,0,0,0.000635906,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","9","LINGO2",0.00331632653061225,7e-14,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 9 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs11030104","A","G","A","G",0.041,-0.00224741,0.792,0.796365,FALSE,FALSE,FALSE,"UKB-a:360",0.0030564,317754,0,0,0.462149,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","11","BDNF",0.0038265306122449,6e-28,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 10 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs11057405","A","G","A","G",-0.031,-0.00384795,0.099,0.105946,FALSE,FALSE,FALSE,"UKB-a:360",0.00399768,317754,0,0,0.335777,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","12","CLIP1",0.00535714285714286,2e-08,"kg/m2 increase","Body mass index",FALSE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 11 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs11165643","T","C","T","C",0.022,0.0027388,0.583,0.592305,FALSE,FALSE,FALSE,"UKB-a:360",0.00250267,317754,0,0,0.273802,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","PTBP2",0.00306122448979592,2e-12,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 12 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1167827","G","A","G","A",0.02,0.0127853,0.553,0.564776,FALSE,FALSE,FALSE,"UKB-a:360",0.00248411,317754,0,0,2.65041e-07,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","7","HIP1",0.00331632653061224,6e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 13 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs11727676","T","C","T","C",0.036,-0.00528194,0.91,0.9041693,FALSE,FALSE,FALSE,"UKB-a:360",0.00417596,317754,0,0,0.205928,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","4","HHIP",0.00637755102040816,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 14 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs12286929","G","A","G","A",0.022,-0.00289907,0.523,0.526759,FALSE,FALSE,FALSE,"UKB-a:360",0.00246578,317754,0,0,0.239708,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","11","CADM1",0.00306122448979592,1e-12,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 15 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs12401738","A","G","A","G",0.021,-0.00327464,0.352,0.382577,FALSE,FALSE,FALSE,"UKB-a:360",0.00253139,317754,0,0,0.195801,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","FUBP1",0.00331632653061225,1e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 16 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs12429545","A","G","A","G",0.033,-0.00260409,0.133,0.129085,FALSE,FALSE,FALSE,"UKB-a:360",0.00369304,317754,0,0,0.480727,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","13","OLFM4",0.0048469387755102,1e-12,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 17 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs12940622","G","A","G","A",0.018,0.00392423,0.575,0.558575,FALSE,FALSE,FALSE,"UKB-a:360",0.00247458,317754,0,0,0.112782,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","17","RPTOR",0.00306122448979592,2e-09,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 18 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs13021737","G","A","G","A",0.06,0.0160406,0.828,0.828681,FALSE,FALSE,FALSE,"UKB-a:360",0.00326022,317754,0,0,8.65512e-07,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","2","TMEM18",0.00408163265306123,1e-50,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 19 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs13078960","G","T","G","T",0.03,-0.00681303,0.196,0.200646,FALSE,FALSE,FALSE,"UKB-a:360",0.00307272,317754,0,0,0.0266059,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","3","CADM2",0.0038265306122449,2e-14,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 20 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs13107325","T","C","T","C",0.048,-0.0223892,0.072,0.0747926,FALSE,FALSE,FALSE,"UKB-a:360",0.00468161,317754,0,0,1.73321e-06,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","4","SLC39A8",0.00688775510204082,2e-12,"kg/m2 increase","Body mass index",FALSE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 21 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs13191362","A","G","A","G",0.028,0.0128931,0.879,0.874831,FALSE,FALSE,FALSE,"UKB-a:360",0.0037257,317754,0,0,0.000539073,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","6","PARK2",0.0048469387755102,7e-09,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 22 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1516725","C","T","C","T",0.045,0.00128874,0.872,0.863778,FALSE,FALSE,FALSE,"UKB-a:360",0.00360157,317754,0,0,0.720473,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","3","ETV5",0.00459183673469388,2e-22,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 23 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1528435","T","C","T","C",0.018,0.00494532,0.631,0.620275,FALSE,FALSE,FALSE,"UKB-a:360",0.00253666,317754,0,0,0.0512319,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","2","UBE2E3",0.00306122448979592,1e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 24 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1558902","A","T","A","T",0.082,0.0099198,0.415,0.402362,FALSE,TRUE,FALSE,"UKB-a:360",0.00250905,317754,0,0,7.69962e-05,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","16","FTO",0.00306122448979592,8e-153,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 25 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs16851483","T","G","T","G",0.048,0.00782458,0.066,0.0658943,FALSE,FALSE,FALSE,"UKB-a:360",0.00496889,317754,0,0,0.115324,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","3","RASA2",0.0076530612244898,4e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 26 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs16951275","T","C","T","C",0.031,-0.00107903,0.784,0.773914,FALSE,FALSE,FALSE,"UKB-a:360",0.00293436,317754,0,0,0.713081,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","15","MAP2K5",0.00357142857142857,2e-17,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 27 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs17001654","G","C","G","C",0.031,-0.0009475,0.153,0.147734,FALSE,TRUE,FALSE,"UKB-a:360",0.00350866,317754,0,0,0.787125,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","4","SCARB2",0.00535714285714286,8e-09,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 28 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs17024393","C","T","C","T",0.066,0.0121285,0.04,0.0257993,FALSE,FALSE,FALSE,"UKB-a:360",0.00775724,317754,0,0,0.117935,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","GNAT2",0.0086734693877551,7e-14,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 29 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs17094222","C","T","C","T",0.025,-0.00147117,0.211,0.212745,FALSE,FALSE,FALSE,"UKB-a:360",0.0030151,317754,0,0,0.625598,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","10","HIF1AN",0.0038265306122449,6e-11,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 30 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs17405819","T","C","T","C",0.022,0.0150809,0.7,0.702337,FALSE,FALSE,FALSE,"UKB-a:360",0.00269143,317754,0,0,2.10476e-08,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","8","HNF4G",0.00331632653061225,2e-11,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 31 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs17724992","A","G","A","G",0.019,0.013991,0.746,0.73339,FALSE,FALSE,FALSE,"UKB-a:360",0.00278657,317754,0,0,5.14668e-07,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","19","PGPEP1",0.00331632653061224,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 32 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1808579","C","T","C","T",0.017,0.00327432,0.534,0.515006,FALSE,FALSE,FALSE,"UKB-a:360",0.00246232,317754,0,0,0.183596,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","18","C18orf8",0.00306122448979592,4e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 33 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs1928295","T","C","T","C",0.019,-0.00260808,0.548,0.570082,FALSE,FALSE,FALSE,"UKB-a:360",0.00248431,317754,0,0,0.2938,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","9","TLR4",0.00306122448979592,8e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 34 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2033529","G","A","G","A",0.019,0.00602559,0.293,0.28865,FALSE,FALSE,FALSE,"UKB-a:360",0.00272397,317754,0,0,0.0269631,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","6","TDRG1",0.00306122448979592,1e-08,"kg/m2 increase","Body mass index",FALSE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 35 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs205262","G","A","G","A",0.022,0.00203564,0.273,0.268168,FALSE,FALSE,FALSE,"UKB-a:360",0.0027741,317754,0,0,0.463069,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","6","C6orf106",0.00357142857142857,2e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 36 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2112347","T","G","T","G",0.026,0.00189519,0.629,0.640786,FALSE,FALSE,FALSE,"UKB-a:360",0.00256824,317754,0,0,0.460556,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","5","POC5",0.00306122448979592,6e-17,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 37 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2121279","T","C","T","C",0.025,0.00221085,0.152,0.126406,FALSE,FALSE,FALSE,"UKB-a:360",0.00371033,317754,0,0,0.551266,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","2","LRP1B",0.00433673469387755,2e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 38 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2176598","T","C","T","C",0.02,0.00360973,0.251,0.245016,FALSE,FALSE,FALSE,"UKB-a:360",0.00286058,317754,0,0,0.20699,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","11","HSD17B12",0.00357142857142857,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 39 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2207139","G","A","G","A",0.045,0.00517893,0.177,0.168282,FALSE,FALSE,FALSE,"UKB-a:360",0.00329386,317754,0,0,0.115882,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","6","TFAP2B",0.00408163265306122,4e-29,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 40 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2245368","C","T","C","T",0.032,0.00610922,0.18,0.167509,FALSE,FALSE,FALSE,"UKB-a:360",0.00328793,317754,0,0,0.0631593,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","7","PMS2L11",0.00561224489795918,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 41 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2287019","C","T","C","T",0.036,-0.00520003,0.804,0.818013,FALSE,FALSE,FALSE,"UKB-a:360",0.00320133,317754,0,0,0.104306,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","19","QPCTL",0.00408163265306122,5e-18,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 42 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2365389","C","T","C","T",0.02,0.0019515,0.582,0.591821,FALSE,FALSE,FALSE,"UKB-a:360",0.00250686,317754,0,0,0.436297,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","3","FHIT",0.00306122448979592,2e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 43 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs2820292","C","A","C","A",0.02,0.00582301,0.555,0.567524,FALSE,FALSE,FALSE,"UKB-a:360",0.00248327,317754,0,0,0.0190331,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","NAV1",0.00331632653061224,2e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 44 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs29941","G","A","G","A",0.018,0.00124039,0.669,0.673233,FALSE,FALSE,FALSE,"UKB-a:360",0.0026281,317754,0,0,0.636946,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","19","KCTD15",0.00331632653061225,2e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 45 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs3101336","C","T","C","T",0.033,-0.00199812,0.613,0.599739,FALSE,FALSE,FALSE,"UKB-a:360",0.00250704,317754,0,0,0.425449,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","NEGR1",0.00306122448979592,3e-26,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 46 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs3736485","A","G","A","G",0.018,0.000927298,0.454,0.46089,FALSE,FALSE,FALSE,"UKB-a:360",0.00247793,317754,0,0,0.708239,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","15","DMXL2",0.00306122448979592,7e-09,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 47 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs3817334","T","C","T","C",0.026,-0.00240189,0.407,0.407295,FALSE,FALSE,FALSE,"UKB-a:360",0.00250056,317754,0,0,0.336785,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","11","MTCH2",0.00306122448979592,5e-17,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 48 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs3849570","A","C","A","C",0.019,0.00119997,0.359,0.347379,FALSE,FALSE,FALSE,"UKB-a:360",0.0025799,317754,0,0,0.641845,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","3","GBE1",0.00331632653061225,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 49 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs3888190","A","C","A","C",0.031,0.0060396,0.403,0.402427,FALSE,FALSE,FALSE,"UKB-a:360",0.00250717,317754,0,0,0.0159997,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","16","ATP2A1",0.00306122448979592,3e-23,"kg/m2 increase","Body mass index",FALSE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 50 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs4256980","G","C","G","C",0.021,0.00666517,0.646,0.656202,FALSE,TRUE,FALSE,"UKB-a:360",0.00259086,317754,0,0,0.010095,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","11","TRIM66",0.00306122448979592,3e-11,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 51 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs4740619","T","C","T","C",0.018,0.00686977,0.542,0.551275,FALSE,FALSE,FALSE,"UKB-a:360",0.00247318,317754,0,0,0.00547475,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","9","C9orf93",0.00306122448979592,5e-09,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 52 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs543874","G","A","G","A",0.048,0.00520832,0.193,0.207808,FALSE,FALSE,FALSE,"UKB-a:360",0.00303284,317754,0,0,0.0859239,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","SEC16B",0.0038265306122449,3e-35,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 53 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs6477694","C","T","C","T",0.017,-0.00201978,0.365,0.354476,FALSE,FALSE,FALSE,"UKB-a:360",0.0025796,317754,0,0,0.433639,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","9","EPB41L4B",0.00306122448979592,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 54 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs6567160","C","T","C","T",0.056,-0.00291924,0.236,0.234055,FALSE,FALSE,FALSE,"UKB-a:360",0.00290304,317754,0,0,0.314617,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","18","MC4R",0.00357142857142857,4e-53,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 55 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs657452","A","G","A","G",0.023,0.00214381,0.394,0.391205,FALSE,FALSE,FALSE,"UKB-a:360",0.00253069,317754,0,0,0.396926,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","1","AGBL4",0.00306122448979592,5e-13,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 56 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs6804842","G","A","G","A",0.019,-0.00167351,0.575,0.574191,FALSE,FALSE,FALSE,"UKB-a:360",0.00249132,317754,0,0,0.501753,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","3","RARB",0.00331632653061225,2e-09,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 57 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs7138803","A","G","A","G",0.032,-0.00604355,0.384,0.368297,FALSE,FALSE,FALSE,"UKB-a:360",0.00254984,317754,0,0,0.0177807,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","12","BCDIN3D",0.00331632653061224,8e-24,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 58 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs7141420","T","C","T","C",0.024,0.004661,0.527,0.514078,FALSE,FALSE,FALSE,"UKB-a:360",0.00247669,317754,0,0,0.0598446,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","14","NRXN3",0.00331632653061224,1e-14,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 59 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs758747","T","C","T","C",0.023,0.00364145,0.265,0.278131,FALSE,FALSE,FALSE,"UKB-a:360",0.00277714,317754,0,0,0.189784,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","16","NLRC3",0.0038265306122449,7e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 60 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs7599312","G","A","G","A",0.022,-0.00387226,0.724,0.731595,FALSE,FALSE,FALSE,"UKB-a:360",0.00279806,317754,0,0,0.166386,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","2","ERBB4",0.00357142857142857,1e-10,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 61 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs7899106","G","A","G","A",0.04,0.0123982,0.052,0.0506763,FALSE,FALSE,FALSE,"UKB-a:360",0.00561664,317754,0,0,0.0272861,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","10","GRID1",0.00688775510204082,3e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 62 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs7903146","C","T","C","T",0.023,-0.00706309,0.713,0.709534,FALSE,FALSE,FALSE,"UKB-a:360",0.00270622,317754,0,0,0.00905598,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","10","TCF7L2",0.00331632653061224,1e-11,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 63 | "Body mass index Systolic blood pressure automated reading || id:UKB-a:360","rs9400239","C","T","C","T",0.019,-0.0101479,0.688,0.706552,FALSE,FALSE,FALSE,"UKB-a:360",0.00270314,317754,0,0,0.000173999,NA,"Systolic blood pressure automated reading || id:UKB-a:360","Neale Lab",2017,0,NA,NA,"Systolic blood pressure automated reading","Systolic blood pressure automated reading || Neale Lab || 2017",TRUE,"mrbase","6","FOXO3",0.00331632653061225,2e-08,"kg/m2 increase","Body mass index",TRUE,"reported","kg/m2 increase","4tEuYO",2,TRUE,"NaN" 64 | -------------------------------------------------------------------------------- /vignettes/MRBase.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "MRBase and TwoSample MR Practical" 3 | author: "MRC-IEU" 4 | date: "10 April 2019" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{MRBase and TwoSample MR Practical} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ## MR Base Overview 13 | 14 | MR Base is an online database and analytical platform for Mendelian randomization, developed by the MRC Integrative Epidemiology Unit at the University of Bristol. It consists of an online web application available at , and as well as the `MRInstruments` and `TwoSampleMR` R packages. 15 | 16 | In this practical session we will: 17 | 18 | 1. Extract summary data from the NHGRI-EBI GWAS catalogue. 19 | 2. Perform necessary data formatting. 20 | 3. Implement a range of two-sample summary MR methods. 21 | 22 | While we will provide a summary of the online web application, this practical mainly focuses accessing data and performing analyses using the R statistics platform. The practical draws on material presented on the [MR Base](https://mrcieu.github.io/TwoSampleMR/#combine-all-results) website, hosted by the MRC-IEU, University of Bristol. 23 | 24 | ### Setup 25 | 26 | Accessing the NHGRI-EBI GWAS catalogue and necessary data formatting functions requires the `MRInstruments` and `TwoSampleMR` R packages to be installed. These would have been automatically installed by the `MR_Practicals` R package, but can be reinstalled at anytime using the following code: 27 | 28 | ```{r,warning=FALSE,message=FALSE,results="hide"} 29 | #install.packages("devtools",dependencies=T,repos='http://cran.us.r-project.org') 30 | library(devtools) 31 | #install_github("MRCIEU/MRInstruments") 32 | #install_github("MRCIEU/TwoSampleMR") 33 | library(MRInstruments) 34 | library(TwoSampleMR) 35 | ``` 36 | 37 | Note that as the `MRInstruments` and `TwoSampleMR` R packages are hosted on Github, installation requires the `devtools` R package. 38 | 39 | ```{r, warning=F, message=F, results='hide',echo=FALSE} 40 | BMIdat<-read.csv("BMIdat.csv",header=T) 41 | ``` 42 | 43 | ### MR Workflow 44 | 45 | The workflow for performing a two-sample summary MR is as follows: 46 | 47 | 1. Select instruments for the exposure of interest, and prune for LD. 48 | 2. Extract the instruments from the MR Base GWAS database for the outcomes of interest. 49 | 3. Harmonise the exposure and outcome datasets, with each sample using the same reference alleles. 50 | 4. Perform MR analyses, senstivity analyses, and compile reports. 51 | 52 | ## Step 1: Obtaining exposure summary estimates 53 | 54 | ### The GWAS catalog 55 | The NHGRI-EBI GWAS catalog contains a catalog of significant associations obtained from GWASs. The MR Base version of the data contains harmonised studies with the required data to perform MR, ensuring that the units used to report effect sizes from a particular study are all the same. 56 | 57 | To use the GWAS catalogue we can first use the following commands to access a reference dataset containing information on all available exposures: 58 | 59 | ```{r} 60 | data(gwas_catalog) 61 | ``` 62 | 63 | With this reference dataset loaded, we can search for phenotypes of interest using the `grepl()` function. For example, if we want to find phenotypes using the key work "Blood", we can use the following command: 64 | 65 | ```{r eval=FALSE} 66 | exposure_gwas <- subset(gwas_catalog, grepl("Blood", Phenotype_simple)) 67 | ``` 68 | 69 | Here, we are searching for the word "Blood" in the simplified phenotypes column of `gwas_catalog` dataset. We can also search for specific studies by author: 70 | 71 | ```{r eval=FALSE} 72 | exposure_gwas <- subset(gwas_catalog, grepl("Neale", Author)) 73 | ``` 74 | 75 | These commands allow us to narrow our search criteria until we arrive at the desired data. In this example, we will use Body Mass Index (BMI) as an exposure, using genetic instruments identified by [Locke et al (2015)](https://www.nature.com/articles/nature14177). 76 | 77 | ```{r, eval=F} 78 | exposure_gwas <- subset(gwas_catalog, grepl("Locke", Author) & 79 | Phenotype_simple == "Body mass index") 80 | 81 | head(exposure_gwas[,c(7:12,18:21)]) 82 | 83 | ``` 84 | 85 | ```{r, warning=F, message=F, results='hide',echo=FALSE} 86 | exposure_gwas<-read.csv("exG1.csv",header=T) 87 | ``` 88 | 89 | ### Manually selecting specific GWAS estimates for the exposure 90 | 91 | Note that we have multiple entries for each instrument, as sex-specific GWAS data is also available. An explanation of the abbreviations used is available [here](https://www.ebi.ac.uk/gwas/docs/abbreviations). In this case, we are interested in using GWAS conducted on all participants with European ancestry (EA), which is achieved by running the following: 92 | 93 | ```{r} 94 | exposure_gwas <- subset(exposure_gwas, grepl("EA", Phenotype_info)) 95 | exposure_gwas <-exposure_gwas[!grepl("women", exposure_gwas$Phenotype_info),] 96 | exposure_gwas <-exposure_gwas[!grepl("men", exposure_gwas$Phenotype_info),] 97 | head(exposure_gwas[,c(7:12,18:21)]) 98 | ``` 99 | 100 | Here we have simply removed all sex specific estimates. To ensure our instruments are strong, we have to restrict the set of estimates to associations with a p-value smaller than $5\times10^{-8}$: 101 | 102 | ```{r} 103 | exposure_gwas<-exposure_gwas[exposure_gwas$pval<5*10^-8,] 104 | ``` 105 | 106 | We then use the `format_data()` function to create a dataset which MRBase will use for the MR analysis. The function will also present a warning message if any instruments lack necessary information for conducting the MR analysis. 107 | 108 | ```{r, warning=F} 109 | exposure_data<-format_data(exposure_gwas) 110 | ``` 111 | 112 | Finally, it is important to prune the set of SNPs for LD, as using correlated SNPs can lead to double counting and, as a consequence, biased causal effect estimates. To prune for LD, the `clump_data` function can be used: 113 | 114 | ```{r,warning=F, results=F,message=F,eval=F} 115 | exposure_data<-clump_data(exposure_data, clump_r2 = 0.001) 116 | ``` 117 | 118 | Note that the threshold for identifying correlated SNPs has been set to the default ($0.001$), though this can be changed if justified. 119 | 120 | Performing the above leaves a total of 62 independent instruments suitable for subsequent MR analyses. 121 | 122 | ### Automatically obtaining instruments 123 | 124 | If the ID number for the exposure of interest is known, it is possible to extract instruments using the `extract_instruments()` function. For example, the [Locke et al (2015)](https://www.nature.com/articles/nature14177) study is ID number $2$, so it is possible to obtain a set of independent instruments by running the following: 125 | 126 | ```{r,message=F, eval=F} 127 | quick_extract<-extract_instruments(2) 128 | ``` 129 | 130 | ```{r, warning=F, message=F, results='hide',echo=FALSE} 131 | quick_extract<-read.csv("exG2.csv",header=T) 132 | ``` 133 | 134 | Note, however, that as this function uses default values the number of instruments may differ compared with manual selection of instruments. In this case, we have `r nrow(quick_extract)` instruments in contrast to the 62 instruments obtained manually. One reason for this is that the automatic selection includes estimates obtained from a mixed population as opposed to individuals of European ancestry. Both approaches have their merits, though manual selection provides greater control over the criteria used for instrument selection. 135 | 136 | ## Step 2: Obtaining outcome summary estimates 137 | 138 | Once instruments for the exposure trait have been specified, those SNPs need to be extracted from the outcome trait. MR Base contains complete GWAS summary statistics from a large number of studies. To obtain details about the available GWASs we can run the following: 139 | 140 | ```{r,eval=F} 141 | ao<-available_outcomes() 142 | head(ao)[,c(3,4,6,8,9,20)] 143 | ``` 144 | 145 | ```{r,echo=F} 146 | ao<-read.csv("ao.csv",header=T) 147 | head(ao)[,c(3,4,6,8,9,11,16,20)] 148 | ``` 149 | 150 | **Note that when data from MR Base is accessed, a window will pop up requiring you to sign in to a google account for authorization. Please sign in, after which the analyses can continue.** 151 | 152 | The head function just shows a summary of useful columns that can be used to find an outcome GWAS of interest. As was the case for manually selecting an exposure dataset, we can use similar commands to search for an outcome of interest. For example, to search for systolic blood pressure (SBP): 153 | 154 | ```{r} 155 | outcome_gwas <- subset(ao, grepl("Systolic", trait)) 156 | head(outcome_gwas)[,c(3,4,6,8,9,11,16,20)] 157 | ``` 158 | 159 | In this example we will select data from UK Biobank (Neale Lab), containing the greatest number of genetic variants. This study has the ID number UKB-a:360. 160 | 161 | Now that the ID for the desired outcome study is known, we need to extract the set of SNPs corresponding to the instruments we obtained from step 1. 162 | 163 | ```{r,message=F, warning=F,eval=F} 164 | outcome_data <- extract_outcome_data( 165 | snps = exposure_data$SNP, outcomes = "UKB-a:360") 166 | ``` 167 | 168 | In the above we specify the column of SNP rsid numbers from the formatted exposure dataframe, and the ID number for the study containing outcome data. 169 | 170 | ### A note on LD proxys 171 | 172 | By default if a particular requested SNP is not present in the outcome GWAS then a SNP (proxy) that is in LD with the requested SNP (target) will be searched for instead. LD proxies are defined using 1000 genomes European sample data. The effect of the proxy SNP on the outcome is returned, along with the proxy SNP, the effect allele of the proxy SNP, and the corresponding allele (in phase) for the target SNP. 173 | 174 | ##Step 3: Data Harmonisation 175 | The exposure data and outcome data are now obtained, but it is important to harmonise the effects. This means that the effect of a SNP on the exposure and the effect of that SNP on the outcome must each correspond to the same allele. 176 | 177 | To harmonise the exposure and outcome data we can run the following: 178 | 179 | ```{r,warning=F,message=F,eval=F} 180 | H_data <- harmonise_data( 181 | exposure_dat = exposure_data, 182 | outcome_dat = outcome_data 183 | ) 184 | ``` 185 | 186 | ```{r, echo=F} 187 | H_data<-BMIdat 188 | ``` 189 | 190 | ### Duplicate entries 191 | 192 | After data harmonisation, users may find that their dataset contains duplicate exposure-outcome summary sets. This can arise, for example, when a GWAS consortium has released multiple results from separate GWAS analyses for the same trait. We recommend that users prune their datasets so that only the exposure-outcome combination with the highested expected power is retained. This can be done by selecting the exposure-outcome summary set with the largest sample size for the outcome, using the power.prune function: 193 | 194 | ```{r warning=F,message=F,results="hide",eval=F} 195 | H_data<-power.prune(H_data,method.size=F) 196 | ``` 197 | 198 | ## Step 3: Perform MR Analyses 199 | 200 | ### Obtaining effect estimates 201 | 202 | Once the exposure and outcome data are harmonised, we have effect estimates and standard errors for each SNP available for the exposure and outcome traits. We can use this information to perform MR. To do this, simply run: 203 | 204 | ```{r warning=F,message=F} 205 | mr_results<-mr(H_data) 206 | mr_results 207 | ``` 208 | 209 | In this case, as specific methods haven't been indicated a range of common two-sample summary MR methods have been applied and presented. The set of methods can be narrowed down using the following: 210 | 211 | ```{r warning=F,message=F} 212 | mr(H_data, method_list=c("mr_egger_regression", "mr_ivw")) 213 | ``` 214 | 215 | A full list of available methods can be obtained by running: 216 | 217 | ```{r warning=F,message=F, eval=F} 218 | mr_method_list() 219 | ``` 220 | 221 | ```{r warning=F,message=F,} 222 | head(mr_method_list())[,1:2] 223 | ``` 224 | 225 | ### Generate odds ratios with 95% confidence intervals 226 | 227 | In publications it is often useful to report effect estimates on the odds ratio scale for ease of interpretation. When analysing a binary outcome, converting the scale from the log-odds ratio to odds ratio scale is achieved by running the following: 228 | 229 | ```{r,eval=F} 230 | generate_odds_ratios(mr_results) 231 | ``` 232 | 233 | **Note that this analysis uses a continuous outcome** 234 | 235 | ### Sensitivity analyses 236 | 237 | Though a set of effect estimates using a range of methods can be obtained using the `mr()` function, it is useful to evaluate heterogeneity as a measure of possible pleiotropic bias. To test for an average pleiotropic effect, we can assess the extent to which the MR-Egger intercept is non-zero: 238 | 239 | ```{r warning=F,message=F} 240 | mr_pleiotropy_test(H_data) 241 | ``` 242 | 243 | Further, we can obtain Q statistics for heterogeneity with respect to IVW and MR-Egger by running the following: 244 | 245 | ```{r warning=F,message=F} 246 | mr_heterogeneity(H_data, method_list=c("mr_egger_regression", "mr_ivw")) 247 | ``` 248 | 249 | Here we see that the MR-Egger intercept is not significant using a 95% threshold, yet there appears to be heterogeneity between individual SNP estimates at a global level. This is indicated by the Q statistics and corresponding p-values for heterogeneity. 250 | 251 | One possible interpretation of these results is some SNPs are pleiotropic, but the average pleiotropic effect is close to zero (and therefore balanced). In follow up analyses we will look at potential outliers based on their contribution to global heterogeneity using the `RadialMR` R package. 252 | 253 | ### Producing plots of MR results 254 | 255 | We can depict the relationship of the SNP effects on the exposure against the SNP effects on the outcome using a scatter plot: 256 | 257 | ```{r, fig.width=8, fig.height=6, warning=F, message=F,results="hide"} 258 | plot1 <- mr_scatter_plot(mr_results, H_data) 259 | plot1 260 | ``` 261 | 262 | We can also produce a forest plot using estimates obtained from individual SNPs: 263 | 264 | ```{r, fig.width=8, fig.height=6, warning=F, message=F,results="hide"} 265 | res_single <- mr_singlesnp(H_data) 266 | plot2 <- mr_forest_plot(res_single) 267 | plot2 268 | ``` 269 | 270 | And a plot showing results from performing leave-one-out analyses: 271 | 272 | ```{r, fig.width=8, fig.height=6, warning=F, message=F,results="hide"} 273 | res_loo <- mr_leaveoneout(H_data) 274 | plot3 <- mr_leaveoneout_plot(res_loo) 275 | plot3 276 | ``` 277 | 278 | Finally, we can produce a funnel plot for assessing heterogeneity: 279 | 280 | ```{r, fig.width=8, fig.height=6, warning=F, message=F,results="hide"} 281 | plot4 <- mr_funnel_plot(res_single) 282 | plot4 283 | ``` 284 | 285 | Recall that in the case of the funnel plot, assymetry is indicative of directional pleiotropy. 286 | 287 | ## Advanced features 288 | 289 | This practical is designed as an introduction to using MR Base using the `MRInstruments` and `TwoSampleMR` R packages. However, further features are being constantly developed and introduced, which can more detail to MR analyses. For further information, more detailed documentation can be found [here](https://mrcieu.github.io/TwoSampleMR/#combine-all-results). 290 | 291 | ## References 292 | 293 | Bowden, Jack, George Davey Smith, and Stephen Burgess. 2015. "Mendelian randomization with invalid instruments: effect estimation and bias detection through Egger regression." International Journal of Epidemiology In press. 294 | 295 | Davey Smith, G., and S. Ebrahim. 2003. "'Mendelian randomization': can genetic epidemiology contribute to understanding environmental determinants of disease?" International Journal of Epidemiology 32 (1): 1-22. 296 | 297 | Davey Smith, George, and Gibran Hemani. 2014. "Mendelian randomization: genetic anchors for causal inference in epidemiological studies." Human Molecular Genetics 23 (R1). Oxford Univ Press: R89--R98. 298 | 299 | Pierce, Brandon L, and Stephen Burgess. 2013. "Efficient design for Mendelian randomization studies: subsample and 2-sample instrumental variable estimators." American Journal of Epidemiology 178 (7): 1177-84. 300 | 301 | 302 | -------------------------------------------------------------------------------- /vignettes/MRBase_files/figure-html/unnamed-chunk-28-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/vignettes/MRBase_files/figure-html/unnamed-chunk-28-1.png -------------------------------------------------------------------------------- /vignettes/MRBase_files/figure-html/unnamed-chunk-30-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/vignettes/MRBase_files/figure-html/unnamed-chunk-30-1.png -------------------------------------------------------------------------------- /vignettes/MRBase_files/figure-html/unnamed-chunk-31-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/vignettes/MRBase_files/figure-html/unnamed-chunk-31-1.png -------------------------------------------------------------------------------- /vignettes/MRBase_files/figure-html/unnamed-chunk-32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/vignettes/MRBase_files/figure-html/unnamed-chunk-32-1.png -------------------------------------------------------------------------------- /vignettes/MVMR Tutorial.rmd: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title: "Multivariable MR Tutorial" 4 | author: "Wes Spiller, Eleanor Sanderson, and Jack Bowden" 5 | date: "2 April 2020" 6 | output: html_vignette 7 | vignette: > 8 | %\VignetteIndexEntry{Multivariable MR Tutorial} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | %\VignetteEncoding{UTF-8} 11 | --- 12 | 13 | ```{r setup, include=FALSE} 14 | knitr::opts_chunk$set(echo = TRUE) 15 | ``` 16 | 17 | ```{r echo=F, results='hide'} 18 | library(devtools) 19 | install_github("WSpiller/MVMR") 20 | library(MVMR) 21 | 22 | ``` 23 | 24 | ## Overview 25 | 26 | Multivariable Mendelian Randomisation (MVMR) is a form of instrumental variable analysis 27 | which estimates the direct effect of multiple exposures on an outcome using genetic variants as 28 | instruments. The `MVMR` R package facilitates estimation of causal effects using MVMR, as well as including a range of sensitivity analyses evaluating the underlying assumptions of the approach. The methods included in `MVMR` originate from Sanderson et al (2020), available at: [doi:] 29 | 30 | ### Workflow 31 | 32 | Fitting and interpreting MVMR models can be achieved by following the 5 steps given below: 33 | 34 | 1. Obtain data 35 | 2. Format data 36 | 3. Assess instrument strength 37 | 4. Assess horizontal pleiotropy 38 | 5. Estimate causal effects 39 | 40 | Each of these steps are shown in Figure 1, highlighting the R function used for each step. 41 | 42 | ![](png/Workflow.png) 43 | 44 | ## Step 1: Obtain summary data 45 | 46 | The following information is necessary to estimate causal effects using MVMR: 47 | 48 | 1) Gene-exposure associations for each variant selected as an instrument for any exposure. 49 | 50 | 2) Corresponding standard errors for the gene-exposure associations. 51 | 52 | 3) Gene-outcome associations for each instrument. 53 | 54 | 4) Corresponding standard errors for the gene-outcome associations. 55 | 56 | The data frame `rawdat_mvmr`, included in the `MVMR` package shows an example of such data obtained from MRBase. In this case, low-density lipoprotein cholesterol (LDL-C), high-density lipoprotein cholesterol (HDL-C), and triglycerides (Trg) have been selected as exposures, while systolic blood pressure (SBP) is the outcome of interest. Here the suffix `_beta` is used to denote association estimates, while `_se` denotes standard errors. Please note that the `MVMR` can take an arbirtary number of exposures (greater than 1), and that three exposures have been selected purely for illustration. 57 | 58 | The first 6 rows of `rawdat_mvmr` are: 59 | 60 | ```{r, echo=T} 61 | head(rawdat_mvmr) 62 | ``` 63 | 64 | Note that the final column `SNP` contains the rsid numbers for each genetic variant. These are not necessary for conducting MVMR, but assist in follow-up analyses. Summary data for LDL-C, HDL-C, and Triglycerides originate from [GLGC](https://www.nature.com/articles/ng.2797), while SBP data was obtained using [UK Biobank](https://www.nature.com/articles/ng.3768). 65 | 66 | ### Estimating pairwise covariances between SNP associations 67 | 68 | The MVMR approach requires pairwise covariances between an instrument and pairs of exposures to be known across all SNPs for accurate estimation and sensitivity analyses, however, this is often not reported in published GWAS analyses. Before continuing with MVMR it is therefore **necessary** to select one of the following three solutions: 69 | 70 | 1. Estimate the covariance terms using individual level data 71 | 72 | If individual level data is available from which the GWAS summary estimates were obtained, the `snpcov_mvmr()` function can be used to calculate the necessary covariance terms. 73 | 74 | 2. Estimate the phenotypic correlation between exposures from individual level data 75 | 76 | If individual level data is available including phenotypic data, the `phenocov_mvmr()` function can be used to provide an approximation for the necessary covariance terms. 77 | 78 | 3. Obtain gene-exposure associations from non-overlapping samples. 79 | 80 | If gene-exposure associations are estimated in seperate non-overlapping samples, then the covariances will be zero by design. It is therefore not necessary to calculate the set of covariances, although this approach can be difficult to apply due to a lack of suitable sources of data. 81 | 82 | ## Step 2: Format summary data 83 | 84 | Downstream functions in the `MVMR` package rely upon prior formatting of raw summary data using the `format_mvmr()` function. Specifically, `format_mvmr()` checks and organises summary data columns for use in MVMR analyses. The `format_mvmr` function takes the following arguments: 85 | 86 | `BXGs` 87 | 88 | A subset containing beta-coefficient values for genetic associations with each exposure. Columns should indicate exposure number, with rows representing estimates for a given genetic variant. 89 | 90 | `BYG` 91 | 92 | A numeric vector of beta-coefficient values for genetic associations with the outcome. 93 | 94 | `seBXGs` 95 | 96 | A subset containing standard errors corresponding to the subset of beta-coefficients `BXGs`. 97 | 98 | `seBYG` 99 | 100 | A numeric vector of standard errors corresponding to the beta-coefficients `BYG`. 101 | 102 | `RSID` 103 | 104 | A vector of names for genetic variants included in the analysis. If variant IDs are not provided (`RSID="NULL"`), a vector of ID numbers will be generated. 105 | 106 | Using the previous data `rawdat.mvmr`, we can format the data using the following command: 107 | 108 | ```{r,echo=T} 109 | 110 | F.data<-format_mvmr(BXGs=rawdat_mvmr[,c(1,2,3)], 111 | BYG=rawdat_mvmr[,7], 112 | seBXGs=rawdat_mvmr[,c(4,5,6)], 113 | seBYG=rawdat_mvmr[,8], 114 | RSID=rawdat_mvmr[,9]) 115 | 116 | head(F.data) 117 | 118 | ``` 119 | 120 | In the above code we have provided the numbered columns for each argument. For example, `BXGs=rawdat.mvmr[,c(1,2,3)]` indicates that columns 1, 2, and 3 are the association estimates for exposures 1, 2, and 3. It is important to note that standard error columns `seBXGs` should be input in the same order as BXGs to ensure the correct matching of association estimates with corresponding standard errors. 121 | 122 | In subsequent steps, each exposure is numbered such that `X1`, `X2`, and `X3` are the first, second, and third entries in the `BXGs=rawdat.mvmr[,c(1,2,3)]` argument. 123 | 124 | 125 | ## Step 3: Test for weak instruments 126 | 127 | In univariate two-sample summary MR, genetic variants selected as instruments are required to be strongly associated with their corresponding exposure. This is quantified by regressing the exposure upon each instrument, and evaluating conditional dependence using the F-statistic for the instrument. Conventionally, a F-statistic greater than 10 is used as a threshold for sufficient instrument strength, representing a 10% relative bias towards the null in the two-sample MR setting. 128 | 129 | Multivariable MR relies upon an extension of this assumption, requiring instruments to be strongly associated with their corresponding exposure conditioning on the remaining included exposures. Conditional instrument strength is quantified by a modified F-statistic which has the same distribution as the univariate F-statistic. Consequently, the same conventional instrument strength threshold of 10 can be used. 130 | 131 | Further details are available at [doi:] 132 | 133 | The `strength_mvmr()` function is used to evaluate instrument strength in the MVMR setting. The function contains two arguments: 134 | 135 | `r_input` 136 | 137 | A formatted data frame created using the `format_mvmr()` function. 138 | 139 | `gencov` 140 | 141 | A variance-covariance matrix for the effect of the genetic variants on each exposure. This is obtained from either `snpcov_mvmr()`, `phenocov_mvmr()`, or set to zero when omitted. 142 | 143 | **Note**: The `strength_mvmr()` function will output a warning if a variance-covariance matrix is not provided. Please see Step 1 for further information. 144 | 145 | Continuing with the previous example, we can evaluate the conditional strength of the instruments for each exposure using the following command 146 | 147 | ```{r,echo=T} 148 | 149 | sres<-strength_mvmr(r_input=F.data,gencov=0) 150 | 151 | ``` 152 | 153 | In this case the set of instruments is sufficiently strong for MVMR estimation using the conventional F-statistic threshold of 10. However, note that we have manually set `mvmrcov` to zero, which would likely not be appropriate given each SNP-exposure estimate eas obtained from the same sample. 154 | 155 | ## Step 4: Test for horizontal pleiotropy 156 | 157 | Horizontal pleiotropy can be evaluated using a modified form of Cochran's Q statistic with respect to differences in MVMR estimates across the set of instruments. In this case, observed heterogeneity is indicative of a violation of the exclusion restriction assumption in MR (validity), which can result in biased effect estimates. 158 | 159 | Importantly, weak instruments can increase the false positive rate for pleiotropy detection, as heterogeneity in effect estimates due to weak instrument bias is conflated with heterogeneity as a result of pleiotropic bias. As a correction it is possible to estimate heterogeneity from pleiotropy through Q-statistic minimisation. 160 | 161 | The function `pleiotropy_mvmr()` can be used to test for pleiotropy, requiring the same arguments as the `strength_mvmr()`; `r_input` and `mvmrcov`. 162 | 163 | ```{r, echo=T} 164 | 165 | pres<-pleiotropy_mvmr(r_input=F.data,gencov=0) 166 | 167 | ``` 168 | 169 | ## Step 5: Estimate causal effects 170 | 171 | Two MVMR estimation methods are provided in the `MVMR` package. The first method fits an inverse variance weighted (IVW) MVMR model, providing estimates of the direct effect of each exposure upon the outcome. This is performed using the `ivw_mvmr()` function as shown below: 172 | 173 | ```{r, echo=T} 174 | 175 | res<-ivw_mvmr(r_input=F.data) 176 | 177 | ``` 178 | 179 | In this case, the effect estimates are interpreted as the direct effects of LDL-C (exposure 1), HDL-C (exposure 2), and Trg (exposure 3) on SBP. Estimates are not robust to weak instruments of pleiotropic bias, and therefore rely upon the underlying MVMR assumptions being satisfied. 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /vignettes/RadialMR.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "RadialMR Practical" 3 | author: "MRC-IEU" 4 | date: "20 April 2019" 5 | output: rmarkdown::html_vignette 6 | vignette: > 7 | %\VignetteIndexEntry{RadialMR Practical} 8 | %\VignetteEngine{knitr::rmarkdown} 9 | %\VignetteEncoding{UTF-8} 10 | --- 11 | 12 | ```{r,echo=F,warning=F,message=F,results='hide'} 13 | library(RadialMR) 14 | BMIdat<-read.csv("BMIdat.csv",header=T) 15 | ``` 16 | 17 | ## RadialMR Overview 18 | 19 | In the previous practical session, we were able to obtain publicly available GWAS data using the MR Base platform, and perform a range of two-sample summary MR analyses. We were also able to perform sensitivity analyses, using heterogeneity in effect estimates obtained using individual SNPs to identify pleiotropic effects. If we assume that heterogeneity is indicative of pleiotropic bias, a logical next step is identifying outliers which are introducing bias into IVW and MR-Egger analyses. 20 | 21 | We have written the `RadialMR` R package to produce radial plots and to perform radial regression for inverse variance weighted and MR-Egger regression models. These plots have the advantage of improving the visual detection of outliers, as well as being coding invariant (i.e. We do not require all SNP-exposure associations to be positive). In this practical session we will: 22 | 23 | 1. Use the `RadialMR` R package to implement radial forms of IVW using data from MR Base. 24 | 25 | 2. Consider a range of sensitivity analyses, including assessment of Q-statistics and the radial MR-Egger model. 26 | 27 | 3. Explore data visualisation options. 28 | 29 | In this example we will be using a data frame called `BMIdat` which is part of this package. This is obtained using the code from the MR Base practical, representing a formatted and harmonised data frame before MR methods were implemented. 30 | 31 | ### Installing RadialMR 32 | 33 | The `RadialMR` R package would have been automatically installed by the MR_Practicals R package, but can be reinstalled at anytime using the following code: 34 | 35 | ```{r,warning=F,message=F,results='hide', eval=F} 36 | install.packages("devtools",dependencies=T, repos='http://cran.us.r-project.org') 37 | library(devtools) 38 | install_github("WSpiller/RadialMR") 39 | library(RadialMR) 40 | ``` 41 | 42 | Note that as `RadialMR` is hosted on Github, installation requires the devtools R package. 43 | 44 | ### The RadialMR workflow 45 | 46 | The workflow for performing a radial two-sample summary MR is as follows: 47 | 48 | 1. Obtain summary data estimates either independently or through MR Base, formatting the data using the `format_radial()` function. 49 | 2. Fit a radial IVW model using the `ivw_radial()` function. 50 | 3. Fit a radial MR Egger model using the `egger_radial()` function. 51 | 3. Plot the data using the `plot_radial()` and `plotly_radial()` functions. 52 | 53 | ## Step 1: Obtaining relevant data 54 | 55 | To perform a two-sample summary MR, we require a set of SNPs with instrument-exposure and instrument-outcome associations, as well as corresponding standard errors. 56 | 57 | Please note that association estimates for binary outcomes should be on the **log odds ratio** scale. 58 | 59 | ### Using pre-existing data 60 | 61 | Previously, we were able to obtain an appropriate dataset from MR Base assessing the effect of body mass index (BMI) upon systolic blood pressure. A copy of this dataset is saved as `BMIdat`, and we can bring up a list of column names for this dataset: 62 | 63 | ```{r,warning=F,message=F} 64 | names(BMIdat) 65 | ``` 66 | 67 | Here the required columns are `beta.exposure`, `beta.outcome`,`se.exposure` 68 | ,`se.outcome`, and `SNP`. To put this data into a format which the `RadialMR` package can understand, we use the `format_radial()` function: 69 | 70 | ```{r,warning=F,message=F} 71 | radial_data<-format_radial(BMIdat$beta.exposure,BMIdat$beta.outcome, 72 | BMIdat$se.exposure,BMIdat$se.outcome, 73 | BMIdat$SNP) 74 | 75 | head(radial_data) 76 | ``` 77 | 78 | This will create an object `radial_data` which will be used as the input for fitting radial IVW and MR Egger models. It is also worth noting that the last argument assigns RSID labels to each SNP. If these are not known, leaving the argument blank will cause temporary placeholder values to be created, and a warning message will be displayed. 79 | 80 | ### Obtaining data from MR Base 81 | 82 | As any dataset we obtain from MRBase will have the same format, the code presented is directly applicable to data on other exposure-outcome relationships. 83 | 84 | ## Step 2: Fitting a Radial IVW model 85 | 86 | The `ivw_radial()` function is used to fit a radial IVW model. It takes a formatted data set as the primary input, and provides several further user-defined options. 87 | 88 | #### Option 1: Weighting 89 | 90 | When fitting a radial IVW model, we can specify whether first order (1), second order (2), or modified second order (3) weights should be used. By default modified second order weights are used, as they are generally more accurate in estimating heterogeneity with respect to each SNP. 91 | 92 | #### Option 2: Significance threshold for detecting outliers 93 | 94 | A second important option is assigning a significance threshold (p-value for significance) for detecting outliers based on their contribution to global heterogeneity. By default `RadialMR` used a significance threshold of $0.05$, though a more conservative approach would be to perform a multiple testing correction. This is achieved by dividing $0.05$ by the number of SNPs used in the analysis. 95 | 96 | #### Option 3: Iteration tolerance 97 | 98 | Finally, it is possible to set a tolerance threshold for fitting the iterative radial IVW model. The iterative approach essentially calculates an IVW estimate which is subsequently used to calculate new modified second order weights, repeating the process until the estimates converge within a given tolerance level. The default value is $0.0001$. 99 | 100 | ### Fitting and interpreting the radial IVW model 101 | 102 | Using the above options, we specify the data we wish to analyse (`radial_data`), the desired significance threshold (`0.05/nrow(radial_data)`), modified second order weights (`3`), and an iteration tolerance threshold of `0.0001`. With each of these options considered, we can proceed to fit the radial IVW model using the following code: 103 | 104 | ```{r,warning=F,message=F} 105 | ivw.model<-ivw_radial(radial_data,0.05/nrow(radial_data),3,0.0001) 106 | ``` 107 | 108 | The output from the `ivw_radial()` function presents several useful results. The first row of estimates corresponds to performing IVW with the desired weighting scheme a single time, whilst the second row shows the iterative results. The exact estimates correspond to the fixed-effects (FE) and random effects (RE) models. 109 | 110 | Below the IVW estimates the F-statistic for the regression is given, though it is important to note that this is not the same F-statistic used to assess instrument strength, but rather the F-statistic for the IVW regression model. 111 | 112 | Next, Cochran's Q-statistic is presented as a measure of global heterogeneity, along with a corresponding p-value. A high Q-statistic and low p-value can be indicative of pleiotropic SNPs contributing to observed heterogeneity in individual SNP effects. 113 | 114 | Finally, the results indicate whether outliers were detected at the given significance threshold, as well as the number of iterations performed using the iterative approach. 115 | 116 | We can extract elements of these results, for example a dataframe of outliers with their corresponding Q statistics, by using the following code: 117 | 118 | ```{r message=F,warning=F} 119 | ivw.model$outliers 120 | ``` 121 | 122 | A full list and description of available elements which can be extracted can be found by typing `?ivw_radial`. 123 | 124 | ## Step 3: Fitting a Radial MR Egger model 125 | 126 | The `egger_radial()` function is used to fit a radial MR Egger model. The format for using this function is similar to `ivw_radial()` taking a formatted data set as the primary input, and allowing for differing weighting options and significance levels as described above. However, iterative and exact MR Egger approaches are still under development. 127 | 128 | To fit the radial MR Egger model, we run the following: 129 | 130 | ```{r,warning=F,message=F} 131 | egger.model<-egger_radial(radial_data,0.05/nrow(radial_data),3) 132 | ``` 133 | 134 | In this case, an intercept and causal effect estimate are presented using the specified weighting. `Wj` represents the weights for the set of SNPs, and coefficient is the estimate for the exposure of interest, in this case, BMI. 135 | 136 | One point of interest is that while the scale for the causal effect is comparable to the conventional MR Egger model, the point estimate for the intercept will differ. This is due to the dependent variable being on a different scale to the conventional model ($\hat{\beta}_j\sqrt{W_j}$) as opposed to the instrument-outcome association scale ($\Gamma_j$). However, inference with respect to deviation from the origin as an indicator of pleiotropy is equivalent, and the corresponding p-values and confidence intervals will therefore be similar. 137 | 138 | The summary of results provides the F-statistic for the regression, a global test of heterogeneity using Rucker's Q, and an indicator of whether outliers have been detected. These are interpreted in a similar fashion to the previous IVW analysis. 139 | 140 | Finally, we can again extract elements from the MR Egger analysis, such as a dataframe of detected outliers: 141 | 142 | ```{r message=F,warning=F} 143 | egger.model$outliers 144 | ``` 145 | 146 | A full list and description of available elements which can be distracted can be found by typing `?egger_radial`. 147 | 148 | ## Step 4: Data visualisation. 149 | 150 | After fitting radial forms of IVW and MR Egger, it is possible to create a series of plots which can be used for visualising effect estimates and outlier status. In each case, the plots created by `Radial MR` show the estimate from performing the approach with the desired weighting for a single iteration. 151 | 152 | ### Radial IVW plots 153 | 154 | We can initially create a plot for the IVW estimate using the `plot_radial()` function. This takes the model as a primary input, and also provides three additional options, `radial_scale`, `show_outliers`, and `scale_match`. 155 | 156 | #### Option 1: radial_scale 157 | 158 | The radial_scale option determines whether a reference scale should be presented on the radial plot. As the radial plot projects onto a circle, this will take the form of a black curve with reference points. The option can either be set to `TRUE` or `FALSE`. 159 | 160 | #### Option 2: show_outliers 161 | 162 | The show_outliers option indicates whether the full set of SNPs should be shown in the plot, or only SNPs identified as outliers. When this option is selected, and `radial_scale=FALSE`, the square root of Q-statistic contribution for each outlier will be presented. This quantifies the extent to which the given SNP is an outlier. The `show_outliers` option can either be set to `TRUE` or `FALSE`. 163 | 164 | #### Option 3: scale_match 165 | 166 | The scale_match option indicates whether the x and y axes should be on the same scale. This can improve the presentation of plots in some cases. The `scale_match` option can either be set to `TRUE` or `FALSE`. 167 | 168 | As an example, we can use the following code to produce a radial IVW plot with a reference scale: 169 | 170 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 171 | IVWplot1<-plot_radial(ivw.model,T,F,F) 172 | IVWplot1 173 | ``` 174 | 175 | And if we are only interested in outliers, we can run: 176 | 177 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 178 | IVWplot2<-plot_radial(ivw.model,F,T,F) 179 | IVWplot2 180 | ``` 181 | 182 | ### The interactive IVW plot 183 | 184 | A new feature of the `RadialMR` package is the `plotly_radial` function, which produces an interactive radial IVW plot. Using this plot, it is possible to use the mouse to highlight individual SNPs, presenting their RSID numbers for subsequent followup. To create an interactive radial IVW plot, we use the ivw model as an input and run: 185 | 186 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 187 | IVWplot3<-plotly_radial(ivw.model) 188 | IVWplot3 189 | ``` 190 | 191 | ### Radial MR Egger plots 192 | 193 | To create a radial MR Egger plot, we can use the same `plot_radial()` function as in the IVW case. In this case, each option is the same as described above, so to create corresponding MR Egger plots to the above IVW plots, we use the following: 194 | 195 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 196 | Eggerplot1<-plot_radial(egger.model,T,F,F) 197 | Eggerplot1 198 | ``` 199 | 200 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 201 | Eggerplot2<-plot_radial(egger.model,F,T,F) 202 | Eggerplot2 203 | ``` 204 | 205 | ### Radial IVW and MR Egger plots combined 206 | 207 | Finally, it is possible to present both IVW and MR Egger estimates simultaneously. This is achieved using the `plot_radial()` function, using both the IVW and MR Egger models previously defined. Once again the options are as previously described. 208 | 209 | To create the combined plot, we include both models using the command `c(ivw.model,egger.model)`. We can then run the following code: 210 | 211 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 212 | Comboplot1<-plot_radial(c(ivw.model,egger.model),T,F,F) 213 | Comboplot1 214 | ``` 215 | 216 | ```{r, fig.width=8, fig.height=6, warning=F,message=F} 217 | Comboplot2<-plot_radial(c(ivw.model,egger.model),F,T,F) 218 | Comboplot2 219 | ``` 220 | 221 | Note that Q-statistics are not presented in the last plot, as the IVW and MR Egger models used differing measures of Q (Cochran and Rucker respectively). 222 | 223 | ## Outlier followup 224 | 225 | A primary feature of RadialMR is the ability to highlight outliers which may be of interest in MR analyses. However, what we do we do once we identify outliers is also of interest. 226 | 227 | For example, we could remove outliers identified when fitting the IVW model using the following code: 228 | 229 | ```{r,warning=F,message=F} 230 | out_rem<-radial_data[radial_data$SNP %in% ivw.model$outliers$SNP,] 231 | radial_data2<-radial_data[-c(as.numeric(row.names(out_rem))),] 232 | ivw.model2<-ivw_radial(radial_data2,0.05/nrow(radial_data2),3,0.0001) 233 | ``` 234 | 235 | It is worth emphasising, however, that such an approach requires justification, and can potentially lead to a loss of valuable information. Better practice would be to look up outliers using a tool such as Phenoscanner, to see if there is a pattern in the set of phenotypes with which they are associated. If we have instruments for a suspected pleiotropic pathway, we can then fit a multivariable MR model. 236 | 237 | ##References 238 | 239 | Bowden, Jack, George Davey Smith, and Stephen Burgess. 2015. "Mendelian randomization with invalid instruments: effect estimation and bias detection through Egger regression." International Journal of Epidemiology In press. 240 | 241 | Bowden, J., et al., Improving the visualization, interpretation and analysis of two-sample summary data Mendelian randomization via the Radial plot and Radial regression. International Journal of Epidemiology, 2018. 47(4): p. 1264-1278. 242 | 243 | Davey Smith, G., and S. Ebrahim. 2003. "'Mendelian randomization': can genetic epidemiology contribute to understanding environmental determinants of disease?" International Journal of Epidemiology 32 (1): 1-22. 244 | 245 | Davey Smith, George, and Gibran Hemani. 2014. "Mendelian randomization: genetic anchors for causal inference in epidemiological studies." Human Molecular Genetics 23 (R1). Oxford Univ Press: R89--R98. 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | -------------------------------------------------------------------------------- /vignettes/exG2.csv: -------------------------------------------------------------------------------- 1 | "id.exposure","SNP","effect_allele.exposure","other_allele.exposure","eaf.exposure","beta.exposure","se.exposure","pval.exposure","samplesize.exposure","ncase.exposure","ncontrol.exposure","units.exposure","exposure","pval_origin.exposure","data_source.exposure","mr_keep.exposure" 2 | "2","rs1000940","G","A",0.225,0.0184,0.0033,1.812e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 3 | "2","rs10132280","A","C",0.3333,-0.0221,0.0033,1.401e-11,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 4 | "2","rs1016287","T","C",0.325,0.0228,0.0033,4.355e-12,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 5 | "2","rs10182181","A","G",0.5,-0.0309,0.0029,8.071e-26,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 6 | "2","rs10733682","A","G",0.425,0.0188,0.003,2.455e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 7 | "2","rs10840100","G","A",0.725,0.0206,0.003,6.666e-12,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 8 | "2","rs11030104","A","G",0.8,0.0416,0.0037,6.658e-30,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 9 | "2","rs11057405","A","G",0.0917,-0.0304,0.0053,1.22e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 10 | "2","rs11165643","C","T",0.425,-0.0221,0.003,1.434e-13,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 11 | "2","rs11672660","C","T",0.825,0.0339,0.0038,7.911e-19,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 12 | "2","rs1167827","A","G",0.4583,-0.02,0.0031,1.975e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 13 | "2","rs11727676","C","T",0.075,-0.0365,0.0063,6.247e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 14 | "2","rs12286929","G","A",0.4333,0.0211,0.0029,5.443e-13,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 15 | "2","rs12429545","G","A",0.9,-0.0324,0.0044,3.152e-13,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 16 | "2","rs12448257","G","A",0.775,-0.0246,0.0037,3.898e-11,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 17 | "2","rs12940622","A","G",0.4583,-0.0183,0.0029,3.636e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 18 | "2","rs12986742","C","T",0.5,0.0207,0.0036,8.924e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 19 | "2","rs13021737","A","G",0.125,-0.0604,0.0039,5.439e-54,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 20 | "2","rs13078960","T","G",0.8167,-0.029,0.0038,1.423e-14,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 21 | "2","rs13107325","C","T",0.8833,-0.0472,0.0066,1.064e-12,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 22 | "2","rs13130484","C","T",0.5667,-0.0398,0.003,8.011e-41,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 23 | "2","rs13191362","A","G",0.8,0.0285,0.0047,1.092e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 24 | "2","rs13201877","A","G",0.9167,-0.0236,0.0043,4.285e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 25 | "2","rs13329567","T","C",0.2167,-0.0307,0.0035,1.526e-18,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 26 | "2","rs1421085","C","T",0.45,0.0803,0.003,2.17e-158,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 27 | "2","rs1441264","A","G",0.55,0.0172,0.0031,2.959e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 28 | "2","rs1460676","T","C",0.7833,-0.0209,0.0038,4.978e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 29 | "2","rs14810","C","G",0.325,-0.0183,0.0033,1.923e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 30 | "2","rs1516725","T","C",0.0917,-0.0448,0.0044,1.394e-24,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 31 | "2","rs1528435","T","C",0.5833,0.0175,0.003,4.774e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 32 | "2","rs16851483","G","T",0.9083,-0.0478,0.0075,1.85e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 33 | "2","rs17001654","C","G",0.8417,-0.0304,0.0052,5.031e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 34 | "2","rs17066856","C","T",0.1333,-0.0371,0.005,2.003e-13,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 35 | "2","rs17094222","C","T",0.2083,0.0249,0.0037,2.186e-11,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 36 | "2","rs17203016","G","A",0.2,0.0211,0.0038,3.406e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 37 | "2","rs17381664","C","T",0.425,0.0201,0.0031,4.568e-11,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 38 | "2","rs17724992","A","G",0.6917,0.0196,0.0034,7.787e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 39 | "2","rs1928295","C","T",0.425,-0.0182,0.0029,4.318e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 40 | "2","rs2033529","G","A",0.2583,0.0183,0.0032,1.449e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 41 | "2","rs2060604","T","C",0.5583,0.0203,0.003,9.46e-12,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 42 | "2","rs2112347","G","T",0.375,-0.0254,0.003,1.96e-17,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 43 | "2","rs2176598","T","C",0.2,0.0185,0.0033,3.469e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 44 | "2","rs2183825","C","T",0.2917,0.0241,0.0032,2.223e-14,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 45 | "2","rs2365389","C","T",0.6583,0.0195,0.003,1.346e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 46 | "2","rs2820292","A","C",0.4917,-0.0181,0.0029,5.452e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 47 | "2","rs2836754","C","T",0.65,0.0169,0.003,1.605e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 48 | "2","rs2890652","T","C",0.875,-0.0279,0.0049,1.242e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 49 | "2","rs3736485","A","G",0.425,0.016,0.0029,4.524e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 50 | "2","rs3800229","T","G",0.6917,0.0175,0.0032,4.95e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 51 | "2","rs3817334","C","T",0.55,-0.0256,0.003,1.168e-17,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 52 | "2","rs3849570","A","C",0.3667,0.0183,0.0033,1.933e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 53 | "2","rs3888190","A","C",0.3583,0.0311,0.003,3.454e-25,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 54 | "2","rs4740619","T","C",0.5333,0.017,0.0029,6.356e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 55 | "2","rs4889606","G","A",0.3583,-0.0187,0.003,6.58e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 56 | "2","rs543874","G","A",0.2667,0.0497,0.0037,2.287e-40,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 57 | "2","rs6091540","C","T",0.725,0.0185,0.0033,2.138e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 58 | "2","rs6457796","T","C",0.7417,-0.0209,0.0033,2.535e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 59 | "2","rs6477694","C","T",0.3583,0.0169,0.003,1.705e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 60 | "2","rs6567160","C","T",0.2833,0.0562,0.0035,6.684e-59,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 61 | "2","rs657452","A","G",0.4167,0.0227,0.0031,2.123e-13,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 62 | "2","rs6713510","A","G",0.4833,0.0164,0.0029,1.974e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 63 | "2","rs6804842","A","G",0.425,-0.0183,0.003,8.016e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 64 | "2","rs7138803","G","A",0.5583,-0.032,0.003,5.115e-26,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 65 | "2","rs7144011","T","G",0.275,0.0274,0.0035,6.045e-15,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 66 | "2","rs7531118","T","C",0.3917,-0.0331,0.003,1.88e-28,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 67 | "2","rs7550711","T","C",0.0339,0.0659,0.0087,5.059e-14,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 68 | "2","rs7599312","G","A",0.7083,0.0214,0.0033,4.73e-11,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 69 | "2","rs7715256","G","T",0.45,0.0168,0.0029,8.851e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 70 | "2","rs7899106","A","G",0.95,-0.0379,0.0067,1.269e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 71 | "2","rs7903146","T","C",0.25,-0.0235,0.0033,1.103e-12,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 72 | "2","rs879620","C","T",0.4083,-0.0244,0.0039,3.939e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 73 | "2","rs891389","C","T",0.675,-0.0209,0.0037,1.617e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 74 | "2","rs9304665","A","T",0.7,0.0243,0.0043,1.594e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 75 | "2","rs9374842","T","C",0.7417,0.0196,0.0034,7.198e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 76 | "2","rs943005","T","C",0.1,0.0444,0.0038,4.524e-31,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 77 | "2","rs9540493","G","A",0.55,-0.0182,0.0031,3.952e-09,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 78 | "2","rs9579083","G","C",0.7667,-0.0295,0.0046,1.426e-10,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 79 | "2","rs977747","T","G",0.4667,0.0168,0.003,2.182e-08,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 80 | "2","rs9926784","T","C",0.7917,0.0249,0.0038,8.548e-11,339224,NA,NA,"SD (kg/m^2)","Body mass index || id:2","reported","mrbase",TRUE 81 | -------------------------------------------------------------------------------- /vignettes/png/workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WSpiller/MRPracticals/3b8c2e7e82a855bd31d3c71e17ff5cfdea534c16/vignettes/png/workflow.png --------------------------------------------------------------------------------