ggridges/0000755000176200001440000000000013606532762012057 5ustar liggesusersggridges/NAMESPACE0000644000176200001440000000424413606450276013301 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(GeomDensityLine) export(GeomDensityRidges) export(GeomDensityRidges2) export(GeomDensityRidgesGradient) export(GeomRidgeline) export(GeomRidgelineGradient) export(GeomVRidgeline) export(PositionPointsJitter) export(PositionPointsSina) export(PositionRaincloud) export(ScaleCyclical) export(StatBinline) export(StatDensityRidges) export(cyclical_scale) export(geom_density_line) export(geom_density_ridges) export(geom_density_ridges2) export(geom_density_ridges_gradient) export(geom_ridgeline) export(geom_ridgeline_gradient) export(geom_vridgeline) export(position_points_jitter) export(position_points_sina) export(position_raincloud) export(scale_alpha_cyclical) export(scale_color_cyclical) export(scale_colour_cyclical) export(scale_fill_cyclical) export(scale_linetype_cyclical) export(scale_point_color_continuous) export(scale_point_color_discrete) export(scale_point_color_gradient) export(scale_point_color_hue) export(scale_point_colour_continuous) export(scale_point_colour_discrete) export(scale_point_colour_gradient) export(scale_point_colour_hue) export(scale_point_fill_continuous) export(scale_point_fill_discrete) export(scale_point_fill_gradient) export(scale_point_fill_hue) export(scale_point_shape) export(scale_point_shape_discrete) export(scale_point_size_continuous) export(scale_size_cyclical) export(scale_vline_color_continuous) export(scale_vline_color_discrete) export(scale_vline_color_gradient) export(scale_vline_color_hue) export(scale_vline_colour_continuous) export(scale_vline_colour_discrete) export(scale_vline_colour_gradient) export(scale_vline_colour_hue) export(scale_vline_linetype) export(scale_vline_linetype_discrete) export(scale_vline_size_continuous) export(stat_binline) export(stat_density_ridges) export(theme_ridges) import(ggplot2) importFrom(ggplot2,Geom) importFrom(ggplot2,ScaleDiscrete) importFrom(ggplot2,Stat) importFrom(ggplot2,StatBin) importFrom(ggplot2,draw_key_polygon) importFrom(ggplot2,geom_density) importFrom(ggplot2,ggproto) importFrom(ggplot2,layer) importFrom(grid,gList) importFrom(grid,gTree) importFrom(plyr,summarise) importFrom(scales,train_discrete) importFrom(stats,quantile) ggridges/LICENSE0000644000176200001440000004317613606371763013101 0ustar liggesusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. {description} Copyright (C) {year} {fullname} This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. {signature of Ty Coon}, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. ggridges/README.md0000644000176200001440000000467013606434665013350 0ustar liggesusers # ggridges: Ridgeline plots in ggplot2 [![Build Status](https://travis-ci.org/wilkelab/ggridges.svg?branch=master)](https://travis-ci.org/wilkelab/ggridges) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/wilkelab/ggridges?branch=master&svg=true)](https://ci.appveyor.com/project/clauswilke/ggridges) [![Coverage Status](https://img.shields.io/codecov/c/github/wilkelab/ggridges/master.svg)](https://codecov.io/github/wilkelab/ggridges?branch=master) [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/ggridges)](https://CRAN.R-project.org/package=ggridges) [![CRAN\_Downloads\_Badge](http://cranlogs.r-pkg.org/badges/ggridges)](http://cranlogs.r-pkg.org/downloads/total/last-month/ggridges) Ridgeline plots are partially overlapping line plots that create the impression of a mountain range. They can be quite useful for visualizing changes in distributions over time or space. These types of plots have also been called [“joyplots”](https://twitter.com/JennyBryan/status/856674638981550080), in reference to the [iconic cover art](https://blogs.scientificamerican.com/sa-visual/pop-culture-pulsar-origin-story-of-joy-division-s-unknown-pleasures-album-cover-video/) for Joy Division’s album *Unknown Pleasures*. However, given the [unfortunate origin](https://en.wikipedia.org/wiki/House_of_Dolls) of the name Joy Division, the term “joyplot” is now discouraged. ## Installation Please install the stable release from CRAN: ``` r install.packages("ggridges") ``` Alternatively, you can install the latest development version from github: ``` r remotes::install_github("wilkelab/ggridges") ``` ## Usage ``` r library(ggplot2) library(ggridges) ggplot(diamonds, aes(x = price, y = cut)) + geom_density_ridges(scale = 4) + scale_y_discrete(expand = c(0, 0)) + # will generally have to set the `expand` option scale_x_continuous(expand = c(0, 0)) + # for both axes to remove unneeded padding coord_cartesian(clip = "off") + # to avoid clipping of the very top of the top ridgeline theme_ridges() #> Picking joint bandwidth of 458 ``` ![](man/figures/README-diamonds-1.png) ## Documentation and Examples First read the [package vignette.](https://wilkelab.org/ggridges/articles/introduction.html) Then read the [reference manual.](https://wilkelab.org/ggridges/reference/index.html) ggridges/data/0000755000176200001440000000000013606377157012775 5ustar liggesusersggridges/data/Aus_athletes.rda0000644000176200001440000001165313606377171016110 0ustar liggesusersBZh91AY&SYhc߿o}oy=k;WNVx"$gKw\iS4i5=f@LRzO0iL5`ɨ@P44d='B) &*@C@C@HC'=&i 4M@F4 Ph@)$e=Gꍩ4h@2FFh@ѡ F4 bh2=M0 Fjy&ڦjzQOQLi OQڃCOHCA 1iq!,cͺh1!ûiN)q'nNNt#8j*t`i|;91'5P&l?N١dbx}*`(L`zhQm9Qה] "D,$=Z)yd"r&m4;EI2@%g )]]&kkjw/T8 lͦ4 MCr0n~@vD$ n*;VPo`eH :(h+d]]xWW !we,-## *6zUS;g6oQQ-ɮ&2 .YFZOiB9Xl܎KS 79 FijDBR.Rl۴ bYdvF,;)r1CVccf2^h1XH2ZF=x!F(uNǽOܟqE<wtjbm/ossų$-`WĻ[sAФ+oPxQJj@ xA*T@žiHI  2qXHJ+"!bƙ*bUr%iAIjg*d*,XDLB!\H*[")!TUIi"\iTk%HaVrS33v4⍃PQ% +$480EC#T @̕E#H$ S%#9PT*B,.Q-1*2@`+P4e2gaa㺛nO^En-lY|?_99#w)q PԶD MbǍޞ+ŗ&g:},,l'A7U`g,~Ug8aт\e@0mRdtn9t*]O99=i:~VApwe% §p7@ ј2 j/#m8ܞqf]e4,pH"U 86@8j3Ec>]yoMdG_bbҔVQb b [Fp)\ UUbR mܠLk5V[ 5s9:e9 U|\Yh˝[XEbt{YFfŧ%)Zgg弰bࢮ+$!$*@5&j[FQ c #bv7.Q&sjtuS/Ȣ]R,SnS-4 D3 L0ύai*kr'kZ?)rĸ4 + J>9Ip5ӕ'IU{oW^_9 aiq0s.3WgtND01S>h_%͟PjJ5pL,[B @R&&=`cv.EܤeJ! -ma5܂d8fN9|!v5iJVR,m"=;<$i`ƍUi7uPOt3n:pX·I[z%K7nη;p]R*nO1gp\n/tU Zal+eǀfDnV+\Tpkbz,[O%lC2"X&rn%߃z#@M.2x!;)p/@ ERe$jis*Z̕ @ )tUeT:֨j TBճ:Xd*jI# K`F52VVJ"aF,:bE(7\lBxXck5IifCXgu%XJJJ,L+MN7Hu:>-cȺ9Q松뛚/u)XlusNn^:ΕU@D"d UmhںuaT-)a 9ES,jm)-}V9\e;VidiLʼnRųezS k$X Etl.SUx>փ>6!h(E;wcF`rGYd1o;pm5EPc*Dc Qն߀lԦ0jf Dj \#LԹ)-N)yUEtM[mU85<&؟]^JmN.͓ضKsԱԟ׎]޼ks^ |]yd<1#b2sLpG!@0A Y)l nX14sҶ`e+QӼ*#$aW5u`fbp־ϼ 'EcCx:|%R\N.sI̜v\\TB* {֫^lk":I!KC939Lk.Ƥ8OS4V][ MVpQʌsDY̪QfqpMW*5&a5RWSjR!"po;Zھ Z9DJpbB^WHjruw{tBኺ`RBJnپ};*8"LBCQ_^=@4@xx|hq9 lfX޽v:3o!8yʀ[eJ[R(X&25Qf@(xtz Ŵ\AYaȍ-ޞl2t0-l?>JJi0MU^!I *X0yj;P$0%Xnj?hsz =-$|_As ~ q,pwɆ^k|h4;'[@@03TP3rg ],D/nE8}_g<|vKI2IeXo+:_úQ(xdTPLz!_*0TD:~ߒ^FK\ ɤy9])762:9[UzUM(pC) *Y |Y6/."S.JVn6gP(klZu$1 MJN];m d+DX 7jީmms}[oAMtu` -@p/{jsEi)l)gh1TQy/Ԣ$ ϊGHz󲷆z{=_*@>u_[\L-1ɞR=31=2ZGGx$F).c(TDEh3iv)D Kw轒K[ 躴 +K }GKs~YZ~xPQُGGfYA <ތ[nrS:u*,CD3P;`t:LZ(DP:*/wphtaؕc{R^omvtP%MNmh0 B}@(̹6n݉W8&l^Ѕ| O[aH!WbR=i2\ӻVr.N|,;rw@ 4m)(N;iY?udG;v˘5TX dY$r\h1RA*P̦A*|4i!iH Baf{G/beMkCcy]o$Y  F(H "H, @(Q4:hr*X"6O& XWH(^J\`0_zύ J 4+R$f-DIjk"yV!*|6Cm@@4 qA@?௵$3QN0d¦[/;+X]$мjeyM=rBƇD 7E]VuzY=<{ ̌3nz1+Ws4 j:&mAձއ|U.Pcz,&HJvDL W&}i JEDDC>s6^,@G{vYYohNc K$!%Y$ӯ3cc{w=VĜAxW`Aw&'fhhL]W>I ;]JB./L-̸,wrL6m~}y6{"1^";d_P*C8Pm 6WOc"M8NC7-hu?$xU> kmm4(Ѡ2AJ(P/lR (5@ (h"Lku`Հ;LSÔpq>$`Bh0A`#A d'zi6dA=L ڏDF=@@d )JT  4hd h ѡ22aidh@ShBTM @44Pɠ @@4hbh44 US#z&A 2= 2a0dhi#@1 1 #M0 M 221C?J*Bi&Sę4ddjzm#M51Sj Ѡ 4hC "Bhb)OJ~MIhzM4 M4 C@4 hh 44է"DW\Cw%ܽYi?ɺ8jj8Ё 5Ttɉ3%`rfKL Nɞ]-*GSMj>7Χ n{ǚ@5b.hX?zK'Zq8Ї]OCa`v?oM {jb4t6}6^T9PQFy$mzY{<~߼s}*}ovG~_h:G߾߽O?|K"J7/s^; {Lq]lzl^8t[5mGؾk%Q{YBX*MERIj'bR/Wl",H1$a!RVф )#'B)}LUU`LWbh)/(zfĉME^L'&&4Oc 9N[& d2jhMlLɣI;1&ܓL'9y' rz9Spa<;ytO.IӢi؟m$ӂl]p. ݥ>$4ИŲiLpOblrmNN]Bv'f|&4N&ܚ&4M;N=La8}DrrO]-$E. |hDco6NzDSiܝMI4&6L&0)iiy'dؽ ҝM46n= B{0Oʚ'/NrM;'g.䜰ڜ$J{8'$ǒv{6ǒw'gtLSd{ɢr'Np/*pO;N&;D9i&jtpM&&9&'*c a<drĘ=a7)L}ה2rN= liSĚSc)m? '/btNOgD>r{ɶ=ҜѲy'I=i4ڝ)c ${0͓|clcb-14ƉI<&ޤ$䝚SN_d<4Na9'jha4NO6'DjhӒiӒm!*o0 39;v={9{YafUd"I"&[Q!Yȇ&blUiqFaq%!**%Ff)a$hB+IJEVW+IiVlZX"J"AbbrBlUD"ZTXJBRʄUlj"Q$D "YVEpJaaFi %%rY$jrAbĉDj" E!QWHeDRDVR%"G EZZq["ZVqV J JF&jQ"B\XRiq!FED**YIAJE&ŌaRED342_c3u>5 F@w/3 G3sIA,qFEqj*k"hrG q"lQ\I@''s|_{zn׏ן #ȹ$kgLaB, b~X &?~mft?0IU4UŎFc  DA\( 5ñٌ[/Q^_<η[+nO&g~@ D!,^!+ GdE@: eVJV;Ny>[.C~ 6Ώ*4YA@ ;\P 6D@]gn j/}~E$˜1LT0)b)1(01L)0))1L ˜)0˜ 1LS˜)1)b )aLS1LS1LSA1LSLS,S,)bS˜*XS b)0b)1L)a)0 ˜0)Sb) ))K˜S,AU bbL)1LS˜)baLS0S˜ aL 0)1LS˜"SS,S0bS1LS…aLSV¬SbS)bbA`S1LS aL aLAb1LS bb 1RLS1L"0)1L)b aL)bdS bbS1LJ1LA0S1LS1L)`)1LAaLS10S1LJ0)aLS˜) 0)b 1L)aL)bK1LS b S˜aL)0)0)00*XS b bQ1L)1LAaLS1L)b1LS`)aLS aL)1U`};wc 0|~o?ij\:.ٸnN84 B݃kKoG'  > A҉`e PIM ,>Q4&DLgjPi;5_{O7 uz&}ݬ6Ns:V}.mFkJNkBz$mHQֈD4Lh[0 .^MJT'*X)3X-WP!hBxk:#O;9:q ˬ3$q7n;5nc^[47*=BrçKb@wy;5ɬi{Wu&yOu`%Vm[CV#M @+!֝$%jt+hdډ- OHH5Ji@UW25&4%5 * J_n9*y6A:G""-Փ"!dcB@yDD`t^+v5u|QjjOHH!5 UBTގ~9>=8,iϡL*gfpDDDa9pݢD@]V<SBDgezZ}?ѷ|7۾뾺a%ZI~_]V EWJ᥏ )Zͧ01gdye D8BeTa* ZP BA!q]{fD}-ӿ\&S~`gLD4t 3 pXx榿Ftr43 0) 0,V? DD |_~]['Nm<"mRDols|!UW!2X_fr\^fTϪ">k!K<5!f j >T,<:q :bʢCh\pTVVNj!g'! gҎ ∴Oڻ>#1|1Qjeuc~=Zgp븝ekZ ~dQ5(Ɏs[ALb[ .6aJ Re|VqbA{\ezx 4J@Fa ďc"sPbdq1:'{y Hm .9D C 9C՟˾Ov pw&Y۠gv vƌv`p#0H  WnlVl*jM}g)Y0}}}ESQAEWNY=<,ȉfLS2@txx*bQb `JbҚS?Adv5MY5F]22kѮ1Ll@dHMy b4~/ǻO̜߻g2t}?FCjpSyx-Kt'djj9uMr5%ܹbJ-.!0Pk:Jn0UX,gJ!0[[7'QMQe$ :J* xb;1݀S1؛&қ&0tM6M'JmMÖ0N&v&:r&1Ra6Lv&ɍD5M~3=5W02P&ϲphAH"}1Oҧަ1L)0D0A{y}_'Oww2Co oRm( C|p ܜMTRa31}tb:PN"a8F@ ^@uCi +U&*f}#!4==5RN4؇'H6+~?̫)ꋙ589߬K~: w&/u<9w!wݍN={4:&0J(ۗ!#h ,%/ }LwVːd iObܟ/Bv([9qjdޒkOaiv5_7 GӉ57,Ȩ2~QiW`../$m)2_s"=G!g枯qZ`y#!?F.!'ǓHŮhc8AgZecțXٓ< qB\l鏵yb_Gp㾫n?xm[$6]h5ak9%TCG d_7",nRCY5ߥ 3Wg|I'_BŪU8끅Ar|bjA?0jN' dyeΖC%*>CtЄ'*猂N`K2Bd#td>!rem?n:˻\rpu&KHW6ڜ\*VT_ R tٱ 8`wSm?(WXq fՆ˗ mJdpa}{a] `~8B!'f|tarƹqjGNN<FKS4v5ӷå\4<0sJbVa5jY*ȓ8FG6c2{5'2}?r}<;Xdq!`C ²-@aOGnoEczWhfԍaKݠ=1f+ b&2;ٔY^} K xMd{=ЄaF¸S2D-6LYe짳f-wSNb?wa:g[K sRhkR89lak;#u=p~.ĝк!$2;l$*[RW98ć)S5HKY)H_eY3i`[Ӯ4MCqw;nYjΕjG8"y}+i|AmǸ5HקF dذAٜ&1ѐY|1ܨ;ń*mo[՛zڑ(n-vιYrrcPʩ OBzGHkh9ڮoI|bxyd}ʒ7F)J#fOP B(oWߊ9mJnweQH|9|ŃgƯIeWOW2./^TVuygGa]juuK }?pz۲Cۇpq.Ϝ.v]`a9AACDWǯ7&NnҔnz:~_Eۓ O3`_$p%$$cz2iqyfnn"%5Z"i~c)(2! X'` m o.Ho~%ׇ) 0Vd:]`-jq=VK_:nN<3SMv&cKnm=b)xWT |ٽP/Ư9Z:mߘ"?{H˕ʽwuȓ35Nq ],tÃw],ӐJIB~ P[NXKA)2(BS\T2D%jx"0(=T7t#@*z'hbq\ஐlэ\d3JRsɞR,X9tuWo1ćyxŭ`!QY{ӭ m˼|[X#!G.uƜ#Z' DkfAJr!Ą,Nn[ ;l4Y"ww;?0<#;̼JuN+z`pcOj;lJ~4qdә!]H;;[NTq*S} =DP!`hvעs(5 9:+:SqܺDŽx%)}ybLܶ?6zWYMAzbӷrq>Dpg 0BE"զ Sn絯:Sm])Z.'`Dd FZFF\/Uq,6y Y$25j{KPخ)QEvٳ*ݮ4cjco܆1(Z:W^nۑln.`-B9ޚ]ɬYŜNmYIgo! n?.%*Jbdž[1\*oyH92z|sQ|ȗdeU EI,+Mڦe˱}EKu^2V =,[p+ȧך}OxUxZ!7ŝXݗn,8a%- 4 l6ۖWK8c7'C]TcSӁ~b7tuõ DڹLF5%iTRkLGŝ]ۺRcSԿ-Yp{vW7 ժOOszeͺ1B>p2r[&M9pѕFAKktRMikkyb)t*[ž3>KpK|$o\mB-Ƈ?nq#A::9uv/&|x-Zͧ\h}(p| m{sL.:k EWvGAԧ4ͧ-l?˕zʁa\HP[;  ܛvy ݝO]׷G^hNwz2؛rcIp[U.bM>߰޺#VX,T066h^޳{% NsgN܅/RaH[@e 䁂άuGDuxfr!yt b}Z5 HC4ya2g WŮt*.yНִ+%M{8ޚoJ$-TgwFyG~jD~wҥF^[23fo5BahګjޯL(uwȂ2هLg7zʆЭE)I5 u̪'Z]YWdvq1hE ۖ+~Ks]1yJ)ޮhC6sq0,nzF)CS8Œq ԒHjuʯʊ)$e_S: eE!x{jSΩUś.u I.sn@:!*P7h׻lԀ:'U(ə*[dvD_=˵Lw@҂>\T{y-+ё3#*JiXru!GZGI)]5r aZ@Cҷ-PqYK thnR-k2IIl[nxgyQuI_( ]/u4w${hk;ԬUkSo>wXLv ~-# طT^x%MÒmܨ}"xuGc]PM{'ן$wO%L>ϔL筥-L.㶾YG[ >dHZ,qE5Ĥ\$HOGeg1S9HӐq :2:/bҔQ8t2.o8ou8ڷGO,┙)|KZGfyG9_8ثuB gpzRW]A}&>'8r٧Y;AR.z$`7Nwʦ ,4:( t&A͌ǩ;{Wvuڝ\<[Nfb-W3c|rD߭r?%Px(f^ɩ,)rܵ_WEwH#g92N,A#s S ԍn=\F.L]jqlq:mCnXK{.ŔwR|Xd+JG/U%OyqWrxO7`٧Q OjUwL W]U 0+v{ﵦC>\_:%Ct|R5l:QB\}B :7L^JvQqH-8^g.xzy7 `$)uc;JntG+7WsN&htN硷yY`\Lg53`39,X)`]R'B;^kj.Y2+#n}~#3tM 5F31x?qiAq/!o?ܝF}~Un:FN.#U/ }|+~Q|ABᘐLwlH/󖗝tar#G$BķMY267B@J vMWJ_vTj_=>}im!o [ ya$˖Q#-pt1CNo#/i̟p` ׶@z)D-x TU_М3{C PMpα2Y&q̦]U_Z3\ojpv/ PH4_nG?NWNyޙo*9J3x[pל`9YXqC ƖM4H|ƝJX{ >n:]7ax | 5[xvf& [;I:z!TgRWgt܀b`==Wn7:| 6h"qs0XgIn.Q/"Q';8Y#zd=0S$PFG_:<0~IW= jvqgIBNtrѼn{w"gFDZ#(tLIdM;j@U?uްe 3_8V r#%mA3|nƪDI\/8|{t.>]%kZ壬ؽ;>C3F4.Vŕ4w$/M]!]9"s6h&&𐣰W#*=d;M(fk(2uq)G0qa˘Y 1`w WЄRu}p#UJ:PL϶f*jRuI)bϻߟx}aI旖7ZQ/P|pswoNr:YNIdwQcm8b(_9K cB";˶gu[rC%IZD ! OLDEdֆ]aLy@:{[qt'B.i9sU*NR"KKED>>Oީ)_S2™)u?ڦ2اTMҝڟJl)5)SE4S50>N1NmN?JmNvS p)*xSJq9܃šSjmM >)覊qM kS*}bMJdf=LaMSTަr){ ~O"U:we:v2ؤ)+AULщa0LSJiMSHM))Of)6SM)OU6%3)OjaNMJ`AʜSJ~ zSʟe;yS;4jxS$SM vš֦ oSE56LT^>;~tvGSvxs?C1@O*n#=^iqOJyxSS z*dwT6Mš)0SSZ`))MJaMaOSjpS)M)NmLSJp8ž<*d3S8TS53SRSSb>E;=S)=zS=b51Oئ"h}{)SMtS)OE;8M|징1NySOe;iOSO*zjg)NE4UlS52g' { Ggİ$^Eq%"|}?ܦ 4S%SËc=IW Cm˛vZ0[ĹZ[bޘ 1XT˜wLOQL))=6)){-0g/E//2kʨ*JbJ XmSS)쩒RL˜߅ _s9x}*08sjktajdz0EP)S)jf"됎s3TaWx_:7ոA~;~]O)aϩ)SC53TyjvTF" &Jbp1&'DT/#C E3 S:41g:6|Bj"" P!1MnSPUL {*|8T@0D%"_k_GOGIySݿ?T;9"շgsVY!^re;*vL)SSEPS"0)T™STOE;)M<)9S1Np{N ҜGM)L)b)iN%4S%;oS%=Tަe=Ȧ)ҟ66()ʘeԧSS%0SZSH-s)Sb%0O|bOȧZSLP0=U0S@꩒S)Oe;NSN6SE5E5ܦ4NvS1LS=~e9TaO!L)L)̧ t)ħ2NU8TS")Sr 5:*jS"ܧ*jl1/W;Mݯ=ח{%Wlc'yōy\9cw?iOE1JE;)?=ژOE9SLڝM)ҚSgH2.~*b))1OE:SNT)7U)N<{BĦ7S fANr̦S*\7- QSJrNRcxS)S)SOM)қSONzS:q)NR r) A0@D gߢ/GOIWˏVqSR{kgSe?*SDq>)4Sb^ؗ0]d76 "D2!==%;wS5;l)<;wN; y7ө)ܧ*N:9W.>yL rENE=4S4}bȦ9h)M7))OjTTS6SžTS)O)NTJtا2Sh0|M<^.89>]t;/{:R]HՒ&0 @s/h +O)XQc@s@ Pgq>Teݖ$24^/gqjo5Y3G55spx+i47U~WqW}8umw3'כ^GMՊX,pN39,>_uoe10x~ 䗭OWcv:oPy!Aٓ::@1OSia0\\)OSjAaNb%5SfeO)MuAMJ3Sz*zt)𧲟E=TL)0SSMN=Osʘާ pS}>=E4Ji(?;Sy))0r%3SNAO )dDK:*q)ʦ:7) >*vSjvSS)SܦSԦ0*b2SN\*r)L}t9&M0_%?|S;iĜ$`tSSJ}p)S4*b)S4> mOȦ*a4")Tģba1U1OL'*cm _S$`驛L)S6壱0SNM)S)ҚS))̧ENq)MtNpNXrN9TOE:S:S4te6e4 |]n؞1ÂpO^XO&6ҚDE1OU<=ma2U8Sb)SNr;+ʘ*|ܓ )AܧN |_bBrƗim0~e9dS 9)uTš)NrdN%0SN))M`U8̧MMOOr) ;)))rSSOOiL<|T지}/?;&1Jt$S8w&S'4 &觅1LSj}|)LS)ҘS9SJhܧاM~wFOLSSŸ"N"{ iؘ'D[Dj9' L&1NxOSJziNrަySOMSܧ*h&9rN5:jl)ƦvSڜ=ž>=ܦ)a1r));SJywc}ת aL vJ~%8S> ltM-iN9SNTNҙ֧)MaM9Se6*wSʚSЧ vS4*vSSuS `" A{~M^ݏ統''Lpwlޯ4χՇs-]d)A]elv~,~ Dhe=|bcD'g4O$8tM)~Ÿ51Oe:Sǂh&OE<)QTnNmMjrNI;=bSH>*{)yS1M)ʝ)Ҙ)bS4Li1NOB}M)14OO#& cwS˜>~P>=T1LS)M1)MSO*\u>U0)ܦML&' SSS a>H4J|a&MSH?)1NwS {ߨhOjz)&%;'brNq9vpM8&SD])r|O pN &؜bx'. Қ'vۖ')4t)L}hjlSH1O)SLSbbE;%L&žz)SO*hڧNbb=);)S)6Oc ħSO'6J}{)Y>3⦔ޕw'2cM9)ʞ|TaiiĜ)cgf4NIv&8px'09'fBhۂiݍ9iNI6MdmSM)4 0W 'gNmMDLSB]ɲl'v͓<8cJcNrç:'u= hw&ܜDdLlh','D;t*]t)݌&)LSjvSjwS<)Nv)ӻm0&606OU1LS=}b;)˜tSS)wS<)NT)ĝS'g$a9&9&10X1LSJiM)piMra1)S꧹Oe6JtS a4NS"ԧ :lS lAN^jϫ;z*zJsUuLҞL'OmM,: 0 o[mkZD0|ovPƷI,!rcY(:@(."aqip0Gԧxxఒ"&ԝeE6RuFK>=e^FBI89]E$[grw4s]xRͼnlfwcFyZ~*bMXIpLh͚S Q bOlOMƉ 4lIJԃzSE4SHjq){r̘nS5=e;OTЧ/ . |8AOLSjS=4Ɖe:Sৣ$œ0;d%0E6|T򧲞hSS "B%8)ʥ4OS =YMNpa0MkSSQLANU=z)Sʞy|O1S by)tL&цS>JySĘަrBz)ŸE>e=)1Oe4܃>J|bG9Se1Ozҡ mM;I4 }r}TSS9SǢL&4Mv'S:SL&={}b}Oa46MPiOzbҟߞ1Iܞ '/4M&rӇ.ͩWS4DiM)L觪r C1e͹<Tp 8 it5/A2)S"uJvL,NšS6NM)I SQTZr~r'w= ~&y8ַJC*7"pE"J& vɄmScM6MDi1&Қ64*ҘM0Lb& cMBa0L&a4&ɀcmVئښSjmM6SM~߿^_YqD0&"aLbLSz-1LM$1F+LiM1L&4i004Mѣ  ca10 & 14Li iLhSIJ~M˜)bSJh6)hDcJia1%)F)bLa6,SjiL)41MқSo{0&6S4)œ)iMg$cN))rmM9S?S p&Sj~NTNTO*laNzN rnS2SZOEOUMJkTUSBAlbA44AiM)SфmOE=.r1ژJb )rLSxiÁp0ҘLSM0)'4Ӓhja6MJc N IM :SJvSLSwS r0S)9SJhL ˜)iM))ȧ93)SrSJb1ҟ=0*x0)Ҧ0O xSL& N44¬&%1Rb)1JLDmLibMM*LUhiǩ1LSKS r0S6%1NTঊb S1MmM)9SpS pSmaZ&.bLSpM )6a1)ʟ)0)pЧRiL)QNTئŌ&)i&HҘ& )0*ɋ4M4Ua&1|ҘS0)M)9SJp)˜t4SJiNœ4iLSJmM)):QܘLc i;)o8p6Dr䜓Nɴ&$l N m¬&)Ę ',l[ iMa0A˜UbҘSH4'e1Ҝz) ʞ4L,>?+&*\)4Sڜœ r' mNb)Sr0ަJwvSE0u4S68)NM))tt; bb()hϳ3޵z>Oe0T&)1L)˜)&ݘ؝)ma4i@ `HCay#d߮.55=iCvH~x1' l(& @iJh& i4 VM?i0baL&lLr)˜œŸ*aNTLSJr 1rl0r pSjy: &6)4P NжSah p)š&bSml&64M`)Jce4jbiLST)2))<6Mj~ʡ 6)ROE8SebLSSmLb).OQL JjS$c6iMd6LSЛlSDc 0M M)46-Bhmhc JmX0SJmLSjbқ0BDSښA1i)bbS8S*h) ~ mNXab&NJb1u0S&iiLSH8Sj`a4L&ؘM0LiOwW1O iLAAȦ?;wJiOe6-0OO[WLc 6M9iӤS9SJiLSS=NkalSJw}c*}TSSN{)S=iFSS}6)œ)ŸU6{hj|XDNU8)N tSj`iOrM))SSma?Q~Κ'䝜К'INIrOR{)mDӻ; ;SROr)ʟB*bvSPbO̧=ORcDʞvRJaL)))FģDcjmRҟ?2;a9cJh1V)8~ bM)!O =N8 fAOJxS> aN6A0E>6)Ortާ"h8Pt꩒J|iL r }TLSOahLbwS󩲝SjiLSঔS<9r9`MS4=~*}mNTOOOO>iM):'$M4Q'Lh??PSNTN?cTڟ:Sj~??L&1bIa1OLSSjhkSЦjh)8)bڜ)ySjl4SJMZSbML)M zͩ+zi9r}*ϿJ;xrڵLβl\ji#k*i'2r/ 51e-!&4RF-i4M(T}W9p.F2^LE'c:iOΦ畧w3+րGH>wxei>cX [nO'&&zőr g UsabFR)Ze=JTd(lzqܑVj.[w?h'R~/s|>R=JfB'{axE?lbj5JTT)y{뇫O%1O)(BPD=~ܹ=ı%Fu9&Et&d0L)LiIĘӆD1LSN4؜4NXi&c&&*I6BbXҚ6ib& )bS0) clD4-,&& 6NI8r᠚&X卶L&L' U )rқ1L&b&hLS *9iULA9SJS fd{JlSbL' p&pSJ}T?wS~SrM; a'"M0N?)ҞšSJiS zҚ )қSM )›S=bOSM{)bL&/I Jl Ҙ!8ia1'50vžSR dS%9Β{=' :&`r:اb Ц)1LS rTiRRT)Ppa0}N9SD=ﵢh&œ8SOʧ)0rژ iNmb&1= hS)ħ qM04SbbSJ{)JtS }TҜM0M14Sꦂ)4Sh8S>%?<)=;)SܧDژ䟲BJd lS {| pS a4A6)p)AO=LSܦ)TJ}TҩSJiLSOOڜ)SibmbL"ĚSLSJb J>0S6*[SD1Lcܦژm(?SB)b)Sja| l0m"ҥʜbXM ))SjmLS6ž?2O6›ڧML*=0SSݮX:DD6L٪{1&1Ҝ))ShE:STSku9'YFfgD6Lr&Irܜ9xrNI4O$tO/'q=;6NҜ NZxvwr:x.N^ |9*So-mjRa=41mDZ0Z'iMLm'tn 0ےbN L8&~8&4D0&ld&OR{)S1'/a9|Z'baN0Mn]Ҟ|X'|Ta<h݂a06jz&Ʌ6c } prmz4N 'Dҝ0rɱݎ[a;L^)f1NScM&i1<*rLb -'pLDኯ1M1L1L)8S> }{)Ӧ0&*^b;1O)SOU1MMNXMD61LpL'Jp*vSE9SjiL*SܦrN{>;Ԛ'$orO&NBd =|?mֿGG3tTc`AcI1h&D4E6MLS ~6SJmN bSJl1Oߩ2)O1Me<ڧL)*hMxSSM)ħMe8){)U1ƘJcpSE6)he8ra=Tҟ:)1Mʞ{pM)SjhLSJpmM›SJabL'$a44)1SSJm)5(Bt:&SbS0ڥ4Mš ֧ )LS lS:OOǖVZ6n7[h00iM6M&&La=Q:lp.\DI:cDv&0a0f6c:ctv!:&IcD;1ؚl)l0EZbl&lӁ'L*]ENNTڛSژ˜M)M6S6қSM):S4e:ta1LSnU`K{vr&)pN*a9f8&HқS0Lr)MMS8SnbS0˜u6žܦ-ah)LSN¥ %SJhJaM vSE:S9)ʘJrb)MڜSJtE1N0*mM*iL' y)ASJru6 )˜JpL' aLS46t!×u<{)bh܍;mp^#wT&iRLSjaM)0_ ذM)ih&ɥ4ƛ&JiJhχ>oJxSšS˜)X)1ښSJb)1Mu?y̦)hҜ))Szœ❅3)5S F1L)0)0)A )9S6SҘ)SObhS|ThSЦ1LSܧ%7)橅4Suܦ7SSRzšMT)AʦMy*s)SE0+Sަ)N?iL{)OSSJca14Lc=?BSOz jS lS"=O>W߾_|{}]HgltۥQ4*b?%H"`}اiMa'N;L2&L0ѢpVbA`SJ~ƜM)S*bpNx?eNTJiM8r0ILSTҝM}}26;8j8SM h))AL @YSGp+3I ưƖ,+ 9|\“ȂccVP@"g=X|ƿ&e/%L)91 !rnE)Y&ˎQFG 3xO ffT}V{Fh`A"bcڛr@40j?R<Z4otH͌ Zph%܄ FhSwN3 \8U?¾@|'fbEP )L)L%XÛ髒 x}k`3@W[o!jq$J$od'Z I ];L;F4N̵$@0)HB`n*:@G8ƳrҶY"Ia+Yth`r͉Ύg0K,_3Ϙ{~n_wv=9ߓw7'8w)w"qqäOFe A b#^u~݌#uq 637?ٵvњbnYѢh6@c 4WHW91PלfЩOT]TG9*"61sQ8go69 z-̺v,E;Zw5/ %n(bAD HYV 1͵ijnT88d jHK6V|Lg ,,bt}R.KU!sWgZ 4LRHA=3Th"D@{W_Ï/7 iޑ"ݺ-C_4iuxއLUW@l>Lww{"t$U'.6m|yWtQMQxa4gOiP$%]Ir:B'8"&rQ&{Viκc9}@o;zޟ˼Kfs]N ZZt뮺а[{KywBuTFkzhMj}8MRXf eW)AA:λ$gR[O)5eBּb6$ fD@B޺D~~IfS)6ԁKL]ҙ}[Um5ҩ4` RpM: whp)݀t4]#Bzj}a5UԷZ's:=3wTfwBLu;{!Oj9IHBOJ:3fIK%oOҵuɏv<? eNsң3ψݓ"2Y`=^i=>C5 ۊwh2TC a͟: 94sk4M{lB10f"{%w5|CGi :Sѵ< #4dfh#U\y?|n F}{%lKM~iq <!v8^1䚖δաM9i-2`n631G𞎊xLJ.Ҹi5ַK8@Ia jey,"3ԂVVRm#Ҫ;9ܺ kD=nύ.K!@옉rSCzWԻC乩 UD4^\ĖR0R7UEFDp~@.]LLLao:Ky[!zq߫gvqW#S5=LmSsWgZyۮF/\hԍHѮo\bG=v V&Kg>?Y0ͯp9d~\rv578ƨSSEPD1PUP 3ps0\p3L̬ə,e3 ((v>'==I&'b VS_]ۺjcϪ*c8ŴQwf@Jc1yH `͊82T(P͈2ܞv8]Yscw|d0aTXZ%԰KẺ9MYE'[mIϕ!V@ӭMy?0""/{unr{ti~yn!X zjUHzll=?(`#؜Xww#rng0e@ab!CS^]*cfrXq13p=Pt)A  " Ix^ԡS^o:qbwͿ5|&${]R/#<+ɞL&W9sm91L3B( Umt5ߓ!jnf1i %E+4Lo ~)$s@O=2F<:;:V0DLC Lz!9lſǓý7,0w/'2AÞӇ,+$7=m{_k8$3 p g|ƴiYf ZTZ{WS3tZEjޠ54*܋5WiR2&كNnqN?vMbRQ:뗡1W3b>kYK% m[[LtR:L~nu<$c4Iqhbf%YPj(Յc"*//2T:$&P_fPg>99Tˡz߬3jr Yrbccz"s=}YaW-skR,8)͓,SZlS4CTSn'9 sd1PW6R3 L&{di"xBM"j$.ʳz~fjϓٴ~M6Fcv\cvzykٹ;6gX.]kF\$4cr1賵LRgMJ&M=!K ?SyE<*irV#:ydtOQwshgZr t9GJ i%v:J(DaZi i5+Lrmq߭521[T5)yVj@)$"U8FcU+>(3V*.H1$ZYֲLDsD+dV̝~GaVlq 6lb5GS-XLD@^$hs@fP]>m9JIbZ VJbeI:"S@.!LD3nQe=geVo{%m+f"\⩋"x9a``5NJi)t 44 f/t>+3-\ߝ  QP5+яiTDF4S0u؂q(k8nuJH/O'"rpstZum밸}d zMkuynu*υ E`3.A,*k5XolẆc3Cgŷe'2-/X! } 2sl~ O6-nXRϕU6뎓XuYw"DmuW17 FT'44#5E do*FTړm'J 5\0 9`V5* H`qɧ&*1QJ4Bȝ$nd4y1DEX¤fDTj|aL0))?L Ʋ'd?O֓rj Bv'"vSv'Dғ4U˱< ܜ1':Dd8&=T p1G\=\;1i^+˜iL)OE4 a1Mz1U5) ܧN?Sʟz*ci)MKŸ}Sy:S0&ɢli6)' a=SLl;4aVmؘLLdSJa0Ŧ0 )4 c02e9SOݓ^LjfSV2a'DI<؜9rӁOzSҥSҚSjsا27MjsxSON&)SM;O= ܞrNǼRw'lpM0'Ț*Mi'gv/,%Ҙʚ&li?S䧂y'rx&Lz =MtӧNT"OBivSS⧅9'dMs'W~0Vq5g'#Bj9_c>L{l2e8+ɔew 3fb@Dd=jFa&48F!Ĭ`3 <_'n}~kAn;l\+E#V-[hȚROo D2bz(ݓwKJ\$hcǎ((4q}){ rc.̓52ڑ-8{5-nM@׫a5YLrɛ1qE}k[0YFB|AP8fu+8<۝nc&rqiW+ !֞Gշ~Μ~UqpTpG \s1fVeY1fYfUYfU3,fW;v~Zf(wlvRwLGW_$?-A0ha"("h=7l)4c.ly;GG!9BI܏eSTy Hf*\3#F4L~.97ghFj밹L05d/2zR2j508An"P]ΈtK2NYB+12)bbER==qvyXfs:*,yؠ!f`,[GA[hs,lR EmEF*;w""z97oPj;Gwr3ݧY1& b0`ϣ;FokŢjKC AX5α]7#)N1zCf D "0%1$Jj2azX,1O\KkVJSFnQ|L71csCocm2_G :ئzݱ2eg͵?Wƞw\קי27gSJxM#WYN)uxtRbddGH#؈DCU@rJX|M}7HJ ĭ):K4l$Dm|yS7/Y8)xeៜrve|w@ P75lv yTlEt4FPchRii7\2`liq)|8EbX#ҲFRci DF̌F>ᣄN*HmHhQ%(QA`$H @z;>?rln\za~q.C͘T;MnoP ?\ !ᔴ&>|W;d~ L;Kh=: jmޭ[SB<CN}[0&00&ExY^Sv7zٶȥ"r{S 5& j^2&iGC<ݧZtQRꯎ1jhLdr eilWDf3$d(SpWm$(WҐ$1X 5H1Xi9ڥ8'<جbdХA TG>Q,ȁ"",y2jbu =}[Rۏ_$Qy|dpZa ;đw8/tİcB~/Ҙwf8-$Z gWQXNjq~YӇWou-ߔe ن[Ƽ&+)!'ަFiy(]5:iUC\!y,bd*6rD5Gߞݵ-61+:SQ@Bf9ѝ._cVƉ<JJ0lRa" _f?_W/tI1t`xN@vs\1íYȊ I S?}]qjG!Ż{VGP KjF^8@o5m;s^e#$&sp3LI z7;lVFqdA㺶QL-F^ƞek]IBhxʡ=[4P?[Gv~|@`333#?41}$ޝ|I 1t%8/;C8^QËiAڀsaS@sRD8"&h 0{Kvfc <^Zc٭TAq;ۋ)rEq >wθq=00t.W%7k}vhmzĆ;"ޚRE;Ө5N#ı E t3.`ʎmy=%uRa+ TV`XD@ !׆cNz /&#TzTkzBu)=ov6Lֻ0~]w"ׄ!Ha4Qxg)/`ǺLPhy6$@ՠjg]جէ+sm`KԺ.31*!ei1z(^6 뮊)7JZp4k_g}e;lǂ>…[A{t%5 Ʀ b}tANJTeJ (o LdMe]/w0 0aA3@{ 0a`3 10fc`azq 4BbjiMl(4LL@=@@ih@ 4hUSLFhJ0`Lɀ 0SSLL&F& ` Fi `4 ` OU*FS<A =M44CL4`CF i#`&#L44d@h44hh@hFM򒔆4OD F5EKq%S"򱤦ޣcgR_YCrHG$$!>='{]陙W뼁<ߩ}n&s`i-sr$ir"*eRhdb[,$Th[ eHkH`q1a&JȜi+)&$)"WʂYiqTZFd\XEAKjrreqF!XTI&bFG!lFdhbEEJ1QQHDajfV{OT uuDNLq,f aJ'VGAg $!%LDPX+!fq2r bZ1k!FrTErd",U,bF!fK)m5|fx3>\ȏlPt|׊SfC:XxB[$ɽo_:$ÂiB#krWeUH&,'@Hb }QV.ZRa3*:}(* 5k,!fBVm͠#Є !eoob~hmQd]؅^{4U"yŤOKzMtZ "]TTܸt5r/lAqeqY9r5)gYtݦd]ZmK yl !L aDD$,JpiRcT[hSr4qnbd >4״54_A+]d-S3DC}UuEˡE2 dI̦|+O=c1$Dc#GF6b1Y5Fx;&jg ҋMZ E)`` Ԉ3a(Ml9t3 D۶S#`,GCiPv#쁪/T*[0Sr8ܰ_{K8>M9qR޷<"]rŘ̌d7~g ϘdD@4.*"溼i"ۇEE9"bH5 D3J !qҎG#L˲<ȔiX-hgThY3VЮc3ae7v0)au<888:sc!cjH4 {kI\m5W۽4JHU-EI8#g?GEG&a*F뤃Gn rxoh OT8-,LLn tWW*$I`ج @B(͒NبSl4, S:*Jt%BPV!28g,V[!z6uFOE_ꁸtV[͟Gӵr0Uv~dVQ>9iejBPDI#@-\|IH^T;j<66ESwKY]*$dI1m\ LrGE0XV$aC06"@CII ƜNBtK0nSُNft{>T.UǓB&r'>4\|Zy @&X1)\6%|JuPY/` Yj_n ]=,q%%Gl#IxpFyQ—B0+cv9,{gsKY/uc.;/*Ɉ Oqǜeҙ( /{1di'Q\osmi 啖5P_~[z*`6pߢ火YiJ6 3]kesKrXn ~<OOG;qfÆ "܎du8`3sAoz3d:͞eFHpآov8xvۡ!2ۿ[ra #T)oN-p!)s 7;jdfvk+ѽC3,\7F )̿L2 ;na `=u yfv:^.C:Yfz۶|ѫJRd ۛ7+3:CVcteU`Y7޾֚RgP}jG)~\QI33kۋbOoif4nxłdsZLlB5Z/ IZԍ0J02G.崦k^ahKu˺#z1}n`A^Gylk|zH.qg/ \`Aˏ5ÉlcpkSGm f+N4km6Tan #vneue~й Wk-$Ld,h27j5Pr9mF[1ޞ7 i xoKe5ڒ͕ 5ZgX{/Y1́ 2|hṕٯ#4(mV'PٻkРbw擹x9:}cZb1_Tz":Bt&}+cXlh!UoQ,DݝܝM?RՅg2-Z@ySUծ֊l7+_n9i:|}vԓvk@6*XصZ6dZ&6O7|dz`-[@dW.'_D9$6@㔥;IAgEx;6(r Y]*.v?=!|ñX Qf}ݟmoRM>[ 5PiyMp/1vz.fNbT*°LR~Sƍ6nVz<9;\.D9UJ c7|q4L{X(4U==nz5.n̡EXv9pzŚqj=$Y@hfC!5KIMEA왞6&A,9lYID q{RSVqr)^`nt sF)X}҅e@y^0ǙY;:OwypY_5B_.qˎ[u>>ܯqq2zA]9Zdiq ^`9FGS}_lw+]'ݚ(ՎmqըהM&P~>Y' rNُ)]BwgGTjt;\P'gzdqűgҔF\=rŜy)db#Vi\.9Ɉs/CLj3:5դn1a6jq?lFbגɢǒnZ^3zI7ryfqlpږz#Ҳo]3a)> 9< wHWe5g-VP4B;ٮarmwuRu*hrIq[onu`[-^;$ә&h%f͹cֳ p`*W]o;INkw'0wۛӯЬʒFV{@ƞ$a' "aattlb%CTTkg̦)ToeRS\n |-Nc)",0am۾[ ãCJsu7-Zw<_s *bbt 1]ŹI-ůrY6 Y[R8tuIsx ]ES۷vVvsQ!wL|Rٲ`5ؘ;K{#S/Ai8Frpnƥ#u /Mn-h.V89i9 ]>yIđΰ_IguE|t9ؖ>M2$JuTߴ:2߁sif7Z-pV 칥i&B\ ʎƕS*Xxmыc[ZQ,q7ᒎ ]Jr/Ȗ3h2Eˋ`T(T歼FՎDYwFp587ah>}{dË/Pd}.#rźe\Dmֈ\Yj߅#8!E; c"2ݠYS }nLmh[XVe W'^; w@S)`ek?1r.B]2\GFcxnf3cLo"}6qrPڣnRHaD[FV'=zvfkGVh\;-Sxc+ݐ7#V;#ݘPFQ1L#cϘ\Uۜ#˶:ͷ%!y W gz@wok(/,RFcY7ajjmJQ-V1wz'>!֟'=ň>! .K=s/7̬d(漆{YFn{A2KD㦦 %,Z@9BxEY$ʤjNbA9zp#m7̅ &5f\MA\Tl^5:oiVҗvD۞5kV=8e;VfYtj6{' R X_ْ'N1se)кձ_$7$tئ6YJJ:V$J[vҞ%'PKws'buݔHF`NO v{Gw5S4$ (ps FOCΡ:TǾcdJy۳è4;NrBїnt."Mqceg sg9(mNnLvb(422t\jeɮS_Q_eD5Zei혥ܿr:bT\CU|$dRrVt|zV-эUp*L8 ."7:%o1υbLag.wJL[‡u(zw#EKcz=(c6sXaȊ:Kѡ kG2k99^혔Њ4o͎pB;kfEړ`X 6#EnR~lEm&F U#9 C {y-旰$syݪXceNX}'ր&QҔS8u1-T8I􎆙-=D3̍ET\ֶt\$Jٙ2om.(3:r,5})jGdaio-ن(Y<£8rLC䜮{i1ݣt 7g9s4".'Oξ:FS6VBm^)[R1+2RGN +םOIsƳ&۶ 2zB85y[/5)jΝ|YÀ.rg;L# ꘦=ۑ/Xݙ J0LюYm ÷E܆u`X؇7;2e%,/nE 񠯾.kM2`|yKM{5N>~ĸs8\O}|Mah[]Q/.ᷠ ^I2o! ܔۦom1Ll"=Kb.3Fڵ[TAS:})qsmE)7m4 1&,غ*v8se}"1Hҹ.g&;d[)0lL8$# RxcXyIٺ"A4SV+?52r $R}%YfM_GiίE.)7g{ˋB^ٱFSL&f3 zsGͤ@/_Q6:Yua:vxK^;LY.7 :z{[JdchŘ Nbhbc*\֩ZuZ4Zє(\n3fSb>)VeYå(6[gFPf ;Hlx$ /ó\o}:oAy{0s9OX냦W%ou`|=ܒ,%#/䲥;y:Ұ]4MJJl(mI,Pu p33ɨݶy&quYEfD%QuG#t$?q]R:4FƲ9".pc )WElj!7Hi2Q Xl2J%RhY-b?sW{vqe|1G~nԝ4jWu> װ21s ؓ!K~={ix<0p s0RId=ËIKPB1zYƚ9-:`ؤr@rjB+T5fE.c[&z !9-M92F8ZaRm@\ZP2Z EmlU |bBVjJZw@@fw3DJ-*(*:i6㦲;Nm;)5mUdkgnh;+d"Ƙ)\"2ʄ$ ,C2$[SDf(q(k @o1Zr:]hီ(C@%gX_bDe*pbz M(L ];:<|~>N谪ԥ+^TbBG:'2>3mξ$!AHGA#0D΍}Smgg`^+WkVl JPDXFYxIJҧ8mkV5qi{n ~LffO߻ A!CS|\%'FLPkwdRˑp|{:ٷ5lXYvҙ/5P 058` 72 B fYUvQ+V:@]c~ đ_Gsl\g'X77gwZ6(Mw]--Tf {]itHpO`BUuJ#f(yxA q$Ecr2H-LdܦN\hQkBƒ j׻`_D.uE]Oyn{:qϧAW92>poD;|\1YwuW[Ri8%rzw^o<R+. qK:q먌oReRS`ؚK @o[5糗k!r.nHA&I |^cБ_1WUKonQMeLO)wqbJ5 Zfr뜆0~K,}{BRI> iA9.'jIdV&Ոftɔ}f,vz$[w/gڿŻvV$ۺ2%,Xb}bBrQ|.(.N2=tQxK]ezoХmj łFHV2I!3 ʛn7[ϒ7)TBuE=z=n(މ'^eπgx8gv( eI²vݗelXwiHkv.iWl{ԣ 2A(ePAeU G4鬮 Ei@Q NKnIYw;7lQ& ŔN7Ry5b˱<?{|M}~ƮY[И/z@9 ~zW5yҍL! zb'÷x?ݖ U'ޚVPAf5m W$ e*R>zzUz@^I≑2"z[:2’KS"FRըfҙ6Xbdn Mcױ^cEvRRĹ})JsF39w|&"o.5sMDQAQ/涮Rrh5@=yǃ DT1K\Nt̲'ަ8[㉯M64Ԇs~;m'%Bx\##*Z0,$ܻ0es3 8]#q64lʖɌbHl4!J}mo|ӷ۲d, &P'Of{b~`ݼ;'4sTբM .廉de8ŭy>Sxzgdh$M4/+c!i)Nk;hty0Er6w'\Km)u%)،/ٶxe0s*I{ef5f biZL4X!ѡFy$(Q$Yix{aap=Y&&Tt"+|1; tF|;N־Zm# ^ȒJ+,7uMsmm_%,;R`av#6uy*Y}+;JWQl hP:leI X ϫ>W$aj͕ڟms.?s2Vf')k9\LՏZkc{Pew[ߺd|Q|js1p_ N1lUD64 0QeO!ch& sA? pQ Z6"I9q)q-4m3Y3MGр?Ns9d"孾nz0<\y[CJTjGfV#0ՑʧE.U3饉sWQ\)_W]4*?5ⴙ",+oO^?{vZawro&I8qs,G4&f .pdVVߴJMѕ>9Uحɻa`YS>1OWa6*Qhu)5W9ǘ9dsFtkt( 18G"5ʥhCtD+Q[p&nka f[Vn7#lأQ8a9Ϫ.LtC[-/cI+RcOֽ&)2dӘ^_fyrc|[Qzː-P6ӆlWJwŵ{1w.^.Ǖ%{(1HY$[`RV*ɪ E;1q9WIp6gb/0P>RR >@זj}uz嬫Ï41ؚbᒔN`즟3AK.PJ.2 !۸s}:H"ܔNΑpu 5kƻu'wSMk-'¸Zq)?cK$!#B L)Dnd[01[TWźiok WSl(qa&"f,X=FܧÕ@@ZlBq*Q5<^..IK:)]kJŮm$TNWM:4gr{h^).^ˑZ,Ωe#^k$5Vw]`yVDE ZW**U RiVkc8at&vk0)%ا]$B @3Ĕ wzFIcrcS͑I}i[sǰ*m-Bf0VϪ KvY*.DY~nNnV*7Tv(n,m:<84z^]!IC\y28IXTqJ6t\%tuv[Ee=P z2H9ziJ1)l1N֜cNK~^]!9X@WEGT]W158xdbz)AHJVzr1ՙbpT3e |khdBI-R31$4>k;sr}|1{^UH}RD;S|3]ã{g踸x+-T9C};w]ziuU]ϏM8$̈́"M6E\q#aDJhaz-p S2%#W F*ݳ1(frFlh5Vҭ6![A׳f=Md+cAy-l!B`+PL ]ʵv,p5ENn{5FI0ѦkҥXxG43|sby ~.hO,lM7#_NU%_G2(b&.8yo%gXzw8Cս 8cuw+z=;9d+黱ܽ{|"0bmʞ @3o_,wf{uy|nn~ _}" D DqEPqWUTGWWp\DQAEUU1qE3PsL\1D>)4;J-%8˾R.Yو.[8 vXOߏʘêڴhP~Aqo5Ǯ攫x6q|Bv_LN\w7,% Hc3f˹ 0'su_aIJv-L]꜀}BIyyVP;vMKS5@uE~6C) nj o19fd.:*c SȐ74?tqBK B8&$:,:[QFӝ:t8"E"BBƈDcD",&$nY* ɺ^ۮ,ssdPl#Q"/SBK>a I|}7mk9A:6vp NSLZF;]thȽ:zuiZ귞pY`\qN/Mb[q^ y+XRH2[3u{aYN׾ f1.arIb8ZPBV+Qa$)]+y~(pwώ,$[!كL/LÕYV"8&C#w!/>Zf.L^w};׺:3mӼFld48B7wZTt6^pԓVtui5𢝌HXDE"ѭ|(Jxxpv1qaD95(Ɇ 9)x#gfXА"%f1JOtO^n6ٿ.4ǃUoaK$DS=E xw׭]xmNyZg'`AkFkv/f;g)n_ӝniuwnRk 0C0&Cס*)چQD4X۱n 35#әfM+B@ 0~SZLC7rҜ9wΉ4nV8\kM̎ץWIJrϝP2Tu^5P;iڗĔrCn TX/:&G}T'FϾjzOnKGbp2e5+!BْۻveQjT0u\@Qć@aԘܑN$~ggridges/data/lincoln_weather.rda0000644000176200001440000001764613606371763016655 0ustar liggesusersBZh91AY&SYEMV#_}{#\ע/|â `@*'ꪀJU< M& "fySCj jzjLM&F@ z 44 Bj24A&5M44 ѠC44A4 j=L=zG'm44z➈1Fȇ40&CGyGꞧz&jmGFFa=&I2& 2jy)'&L0C@mC&P 4@4@4@@h/wֽ׹|Օ+Xa=G:.vMԻ] ѶU\TԘtH jVtřDE9B0Dғ$PsERdVZL&:j~_su $3,iY`c)BpLUH26GV6sZBL#R+AuUi" Qzn`2Gw(Ik}xD@3Xv$X6#LM@":*3Qeg[]3\^: 牷 EW*IZS[:MWk&hϻlsZt$ժG)<t2rԵ4b\WCED1uTvmQͦJLaxQdDS D[/4P5u4d@+GID+4Q+u͊b ̱rRբ/i-e,ƐI<)W5v&PxL c)S A.)ԢD)EpJ2t<{yd2^%Ix'0*A@arktjV=z6׵ zܻI''yȪ1M$..:aACM-уeTTX# f&к]1V6ȼ:,`;ZVSfMr÷ΊP5{1SfJ3fs֓hm^)͛3MlŜᆆp g& j͘hκqi6VFS-fynI1Xc1'jJ6tb\7ÚɊ;XX@1C6dZlb*6smV){yk@ ʰwgÞd")yd/ѠV(#JP4Xz3;CMmyEO!5hg`F~(Γ_s/&9M.nŎcbzj"7y78dÜBxЬC 0am+zXiy~tGXc8QyE0CLI/T_Ѡ|2Q*skda:r(G]@ץW{irLy'B,f RfZz4NcXP25]̏B}-M%+ aiOqy5md*R 5zӓDҭ 5Q_"|\`-U5hmNڨnVznE J1 rub kE.:O$t;g'u^Ad)-HV(CdVYZjfeSn]'$B[RbY:dVRn=ҦXH bMd[O{O~zo)(YO@!Tkɯlի&Y-;^`Bl-X=a+%9PZ'a3]&ľ@+5/LViO;a {Cy6ݥ6NdknB԰ JY%偪 6u؆W1iHZM#OPP`v[cE+Ip?i@v'@))SmkzV,(\rh5M78.`(ԷL̤yt?{wuݎސj{裿zrn$]]CRj}JkR¦ë,^ixU} hm < pPq&_5hDc,bO'`ǍP5#ݒܳ{^-H^ƗHuA v Aђ!d~QxF˅HY\n6ݧlT|!e\S$muV^IJ!ە#Rޒ2c@3q-9 ]\;6p y 8Ta'vA?#Rp0vr (MO@eZ[u1H%^^]a]ی~uɌHa%PqY&Ctݞ _iلCTg27AlNk|T##s'N<3ua\j.:J b/X/JJ/5ߏ}q7PV*;ks]3/ {2YSZ|F2*j-Ʈ  c˕ ӥcܺnG#3.*j[܂jzfdZ˂q@DT^Qrv.y%L}F}̴ z 4[tn֊1l ׿e 4yu:ZL۶QwzOm@ v:,"ܲa|N^LFR: v[<1l;p6aUv8a/bNyPt(.b Pwbr[ZP >l޴ɩ :)M (0siS`>Koǹ[K/W@"ײ NqhW]eÎǪ7Ԫ(%oGHO<,u?ؕ=@U_XSa!gj0'^!P`:Axʤ"ڈ`n]plAXMrb˼iwѷ"^RҠE/>bmw'{]_mOjXʈjRtt;f;+j.8@,d.&!4l}"C%oE47)J:l +mH7)Q2vi-} s,Ʊ2 @ƙjvX1ھb HJ*᪯>M߳{*U[$ךMaE"H1!RK{|Eli<@VR^3A֐/_cZ='*:@6fSؤ60BGfc`:cՕ6e_=6bXdi1s%wi njvN A@DDP󐔓h뗹$-}Ue]>7UPjLՊmħ. M+,r\vEY1AQ6B#B<%]:E# lQYmzPȑQ]p Xd!g:o YT; 3Ѝ#{UZsF&l9p)*$,J0YЀro枕I-$x>}=V &(C(^#S eaWЂȀ " קAILJH'C'![lzDɣQ&']k($y5Cl!ź!P٬ ҪqjȤ5XMsራ9:\`Vpkc1/wugF -AG̜DcC )Ddzf<\{t^{GJ#pJFұ2ETw1s}""";!tZ-Dj&Q-"h( -bP!< 0PH]UJI `Cv B b QBp B BhCƄ ߟ+mZ؇5++I7HY$/3!Ύ6q, @l.  @`meFa$Д(#QfPbˆؐP HX`dT:;;;;;;92^U&LY2=kZRֶ0ֵZ0 " " " "" =kZrs@@l`k[Zzֵ8l`kvP4$P3*c uJ!m+$ d :jVڶjV$!Ӥ5$t@6p^/[z7(F1UUUUVUUUUUUUUUUUEUUy@d@E !T[ hamm(YjUUUUUUUUUUU% ?AH(r AFDVDQ%H)Q  dH)dH) AFDT:P#B(DB(NHu:9+HUUUUUz!IH!Q;PA<$ -UUUUUpB+9@̲UUUU[$HC:tU,UUUUV$Y$RHHbVVEYdUVBIHMuo$o$27olUUUUV&RM͞w~-mmmmpoMYX$~8;Pѭ-PQ-RBoF Ñ D2^_ҹr5 E>5X=Vşȡ+W&b-=ڛcRMVYT3]#aXO4A%E$I2MͣdD%6 ё`T-H*ʲ;,Pvf}7;MgQe#8a"ܻ8 m-v+WL#֪3n&0ḷO-&xk7SQ,J$5t/Dh.kRE;>:Wd7#fum\0ѩLd3KeQ ޔ+tbZ2/ʱnmu[u}Tge]+Ig<+`މrE#Bȳ Y)^b4!IPپ:f=G(imji%ab]H&9bM1 Z8ReXBvAE%~%HTI :lX|K$" /@Qw=iƟXjCDz3)e3gچss!&z`.ajr\J@'! * $X 0(YEAFv jޣWkXS `vM2+Xi8Khꠚti4ob 8 ,84Qߠ:#Tng47" Fqpjb ς+qQHiȤCgy;1ׂ9-mDtJzBj糅QTPրj!`(}$2(ZD.9*eZ#e@/oOM&T:"bI( m]m1B)!,q '(xEFY&5  c m*+I I; E}B!O:0an5ȫrP$ d!`z/.aQ\01E(ΤQH2= J1DEuPR) H"HJ@?kD+ "P,ǠVX:RI!! ?V(. h% BXR2ef1UjUQq*zDDy H4+ YDE|}]{yo9C||9*?\TܑN$rS@ggridges/man/0000755000176200001440000000000013606377475012642 5ustar liggesusersggridges/man/stat_binline.Rd0000644000176200001440000001643213606425126015575 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/stats.R \docType{data} \name{stat_binline} \alias{stat_binline} \alias{StatBinline} \title{Stat for histogram ridgeline plots} \usage{ stat_binline( mapping = NULL, data = NULL, geom = "density_ridges", position = "identity", ..., binwidth = NULL, bins = NULL, center = NULL, boundary = NULL, breaks = NULL, closed = c("right", "left"), pad = TRUE, draw_baseline = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or \code{\link[ggplot2:aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. All objects will be fortified to produce a data frame. See \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame}, and will be used as the layer data. A \code{function} can be created from a \code{formula} (e.g. \code{~ head(.x, 10)}).} \item{geom}{Use to override the default connection between \code{geom_histogram()}/\code{geom_freqpoly()} and \code{stat_bin()}.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{colour = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} \item{binwidth}{The width of the bins. Can be specified as a numeric value or as a function that calculates width from unscaled x. Here, "unscaled x" refers to the original x values in the data, before application of any scale transformation. When specifying a function along with a grouping structure, the function will be called once per group. The default is to use \code{bins} bins that cover the range of the data. You should always override this value, exploring multiple widths to find the best to illustrate the stories in your data. The bin width of a date variable is the number of days in each time; the bin width of a time variable is the number of seconds.} \item{bins}{Number of bins. Overridden by \code{binwidth}. Defaults to 30.} \item{center}{bin position specifiers. Only one, \code{center} or \code{boundary}, may be specified for a single plot. \code{center} specifies the center of one of the bins. \code{boundary} specifies the boundary between two bins. Note that if either is above or below the range of the data, things will be shifted by the appropriate integer multiple of \code{width}. For example, to center on integers use \code{width = 1} and \code{center = 0}, even if \code{0} is outside the range of the data. Alternatively, this same alignment can be specified with \code{width = 1} and \code{boundary = 0.5}, even if \code{0.5} is outside the range of the data.} \item{boundary}{bin position specifiers. Only one, \code{center} or \code{boundary}, may be specified for a single plot. \code{center} specifies the center of one of the bins. \code{boundary} specifies the boundary between two bins. Note that if either is above or below the range of the data, things will be shifted by the appropriate integer multiple of \code{width}. For example, to center on integers use \code{width = 1} and \code{center = 0}, even if \code{0} is outside the range of the data. Alternatively, this same alignment can be specified with \code{width = 1} and \code{boundary = 0.5}, even if \code{0.5} is outside the range of the data.} \item{breaks}{Alternatively, you can supply a numeric vector giving the bin boundaries. Overrides \code{binwidth}, \code{bins}, \code{center}, and \code{boundary}.} \item{closed}{One of \code{"right"} or \code{"left"} indicating whether right or left edges of bins are included in the bin.} \item{pad}{If \code{TRUE}, adds empty bins at either end of x. This ensures that the binline always goes back down to 0. Defaults to \code{TRUE}.} \item{draw_baseline}{If \code{FALSE}, removes lines along 0 counts. Defaults to \code{TRUE}.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes. It can also be a named logical vector to finely select the aesthetics to display.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them. This is most useful for helper functions that define both data and aesthetics and shouldn't inherit behaviour from the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} } \description{ Works like \code{stat_bin} except that the output is a ridgeline describing the histogram rather than a set of counts. } \examples{ library(ggplot2) ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species, fill = Species)) + geom_density_ridges(stat = "binline", bins = 20, scale = 2.2) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges() ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species, fill = Species)) + stat_binline(bins = 20, scale = 2.2, draw_baseline = FALSE) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + scale_fill_grey() + coord_cartesian(clip = "off") + theme_ridges() + theme(legend.position = 'none') library(ggplot2movies) ggplot(movies[movies$year>1989,], aes(x = length, y = year, fill = factor(year))) + stat_binline(scale = 1.9, bins = 40) + scale_x_continuous(limits = c(1, 180), expand = c(0, 0)) + scale_y_reverse(expand = c(0, 0)) + scale_fill_viridis_d(begin = 0.3, option = "B") + coord_cartesian(clip = "off") + labs(title = "Movie lengths 1990 - 2005") theme_ridges() + theme(legend.position = "none") count_data <- data.frame( group = rep(letters[1:5], each = 10), mean = rep(1:5, each = 10) ) count_data$group <- factor(count_data$group, levels = letters[5:1]) count_data$count <- rpois(nrow(count_data), count_data$mean) ggplot(count_data, aes(x = count, y = group, group = group)) + geom_density_ridges2( stat = "binline", aes(fill = group), binwidth = 1, scale = 0.95 ) + geom_text( stat = "bin", aes(y = group + 0.9*stat(count/max(count)), label = ifelse(stat(count) > 0, stat(count), "")), vjust = 1.2, size = 3, color = "white", binwidth = 1 ) + scale_x_continuous(breaks = c(0:12), limits = c(-.5, 13), expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + scale_fill_cyclical(values = c("#0000B0", "#7070D0")) + guides(y = "none") + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE) } \keyword{datasets} ggridges/man/position_raincloud.Rd0000644000176200001440000000333413606436243017025 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/position.R \docType{data} \name{position_raincloud} \alias{position_raincloud} \alias{PositionRaincloud} \title{Create a cloud of randomly jittered points below a ridgeline plot} \usage{ position_raincloud( width = 0, height = 0.4, ygap = 0.05, adjust_vlines = FALSE, seed = NULL ) } \arguments{ \item{width}{Width for horizontal jittering. By default set to 0.} \item{height}{Total height of point cloud. By default 0.4.} \item{ygap}{Vertical gap between ridgeline baseline and point cloud.} \item{adjust_vlines}{If \code{TRUE}, adjusts vertical lines (as are drawn for quantile lines, for example) to align with the point cloud.} \item{seed}{Random seed. See \code{\link{position_points_jitter}}.} } \description{ This is a position adjustment specifically for \code{\link[=geom_density_ridges]{geom_density_ridges()}} and related geoms. It only jitters the points drawn by these geoms, if any. If no points are present, the plot remains unchanged. The effect is similar to \code{\link[=position_points_jitter]{position_points_jitter()}}, only that by default the points lie all underneath the baseline of each individual ridgeline. } \details{ The idea for this position adjustment comes from Micah Allen, who proposed this type of plot in a \href{https://micahallen.org/2018/03/15/introducing-raincloud-plots/}{blog post} on March 15, 2018. } \examples{ library(ggplot2) ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE, position = "raincloud", alpha = 0.7) } \seealso{ Other position adjustments for ridgeline plots: \code{\link{position_points_jitter}}, \code{\link{position_points_sina}} } \keyword{datasets} ggridges/man/geom_density_ridges.Rd0000644000176200001440000001375113606373577017162 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/geoms.R \docType{data} \name{geom_density_ridges} \alias{geom_density_ridges} \alias{GeomDensityRidges} \alias{geom_density_ridges2} \alias{GeomDensityRidges2} \title{Create ridgeline plot} \usage{ geom_density_ridges( mapping = NULL, data = NULL, stat = "density_ridges", position = "points_sina", panel_scaling = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... ) geom_density_ridges2( mapping = NULL, data = NULL, stat = "density_ridges", position = "points_sina", panel_scaling = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}} or \code{\link[=aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[=ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame.}, and will be used as the layer data.} \item{stat}{The statistical transformation to use on the data for this layer, as a string.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{panel_scaling}{If \code{TRUE}, the default, relative scaling is calculated separately for each panel. If \code{FALSE}, relative scaling is calculated globally.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them.} \item{...}{other arguments passed on to \code{\link[=layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{color = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} } \description{ \code{geom_density_ridges} arranges multiple density plots in a staggered fashion, as in the cover of the famous Joy Division album Unknown Pleasures. } \details{ By default, this geom calculates densities from the point data mapped onto the x axis. If density calculation is not wanted, use \code{stat="identity"} or use \code{\link{geom_ridgeline}}. The difference between \code{geom_density_ridges} and \code{\link{geom_ridgeline}} is that \code{geom_density_ridges} will provide automatic scaling of the ridgelines (controlled by the \code{scale} aesthetic), whereas \link{geom_ridgeline} will plot the data as is. Note that when you set \code{stat="identity"}, the \code{height} aesthetic must be provided. Note that the default \code{\link{stat_density_ridges}} makes joint density estimation across all datasets. This may not generate the desired result when using faceted plots. As an alternative, you can set \code{stat = "density"} to use \code{\link{stat_density}}. In this case, it is required to add the aesthetic mapping \code{height = ..density..} (see examples). } \section{Aesthetics}{ Required aesthetics are in bold. \itemize{ \item \strong{\code{x}} \item \strong{\code{y}} \item \code{group} Defines the grouping. Not needed if a categorical variable is mapped onto \code{y}, but needed otherwise. Will typically be the same variable as is mapped to \code{y}. \item \code{height} The height of each ridgeline at the respective x value. Automatically calculated and provided by \code{\link{stat_density_ridges}} if the default stat is not changed. \item \code{scale} A scaling factor to scale the height of the ridgelines relative to the spacing between them. A value of 1 indicates that the maximum point of any ridgeline touches the baseline right above, assuming even spacing between baselines. \item \code{rel_min_height} Lines with heights below this cutoff will be removed. The cutoff is measured relative to the overall maximum, so \code{rel_min_height=0.01} would remove everything that is 1\\% or less than the highest point among all ridgelines. Default is 0, so nothing is removed. alpha \item \code{colour}, \code{fill}, \code{group}, \code{alpha}, \code{linetype}, \code{size}, as in \code{\link{geom_ridgeline}}. \item \code{point_shape}, \code{point_colour}, \code{point_size}, \code{point_fill}, \code{point_alpha}, \code{point_stroke}, as in \code{\link{geom_ridgeline}}. } } \examples{ library(ggplot2) # set the `rel_min_height` argument to remove tails ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(rel_min_height = 0.005) + scale_y_discrete(expand = c(0.01, 0)) + scale_x_continuous(expand = c(0.01, 0)) + theme_ridges() # set the `scale` to determine how much overlap there is among the plots ggplot(diamonds, aes(x = price, y = cut)) + geom_density_ridges(scale = 4) + scale_y_discrete(expand = c(0.01, 0)) + scale_x_continuous(expand = c(0.01, 0)) + theme_ridges() # the same figure with colors, and using the ggplot2 density stat ggplot(diamonds, aes(x = price, y = cut, fill = cut, height = ..density..)) + geom_density_ridges(scale = 4, stat = "density") + scale_y_discrete(expand = c(0.01, 0)) + scale_x_continuous(expand = c(0.01, 0)) + scale_fill_brewer(palette = 4) + theme_ridges() + theme(legend.position = "none") # use geom_density_ridges2() instead of geom_density_ridges() for solid polygons ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges2() + scale_y_discrete(expand = c(0.01, 0)) + scale_x_continuous(expand = c(0.01, 0)) + theme_ridges() } \keyword{datasets} ggridges/man/geom_ridgeline.Rd0000644000176200001440000001103213606373577016076 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/geoms.R \docType{data} \name{geom_ridgeline} \alias{geom_ridgeline} \alias{GeomRidgeline} \title{Plot a ridgeline (line with filled area underneath)} \usage{ geom_ridgeline( mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}} or \code{\link[=aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[=ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame.}, and will be used as the layer data.} \item{stat}{The statistical transformation to use on the data for this layer, as a string.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them.} \item{...}{other arguments passed on to \code{\link[=layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{color = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} } \description{ Plots the sum of the \code{y} and \code{height} aesthetics versus \code{x}, filling the area between \code{y} and \code{y + height} with a color. Thus, the data mapped onto y and onto height must be in the same units. If you want relative scaling of the heights, you can use \code{\link{geom_density_ridges}} with \code{stat = "identity"}. } \details{ In addition to drawing ridgelines, this geom can also draw points if they are provided as part of the dataset. The stat \code{\link[=stat_density_ridges]{stat_density_ridges()}} takes advantage of this option to generate ridgeline plots with overlaid jittered points. } \section{Aesthetics}{ Required aesthetics are in bold. \itemize{ \item \strong{\code{x}} \item \strong{\code{y}} \item \strong{\code{height}} Height of the ridgeline, measured from the respective \code{y} value. Assumed to be positive, though this is not required. \item \code{group} Defines the grouping. Required when the dataset contains multiple distinct ridgelines. Will typically be the same variable as is mapped to \code{y}. \item \code{scale} A scaling factor to scale the height of the ridgelines. A value of 1 indicates that the heights are taken as is. This aesthetic can be used to convert \code{height} units into \code{y} units. \item \code{min_height} A height cutoff on the drawn ridgelines. All values that fall below this cutoff will be removed. The main purpose of this cutoff is to remove long tails right at the baseline level, but other uses are possible. The cutoff is applied before any height scaling is applied via the \code{scale} aesthetic. Default is 0, so negative values are removed. \item \code{colour} Color of the ridgeline \item \code{fill} Fill color of the area under the ridgeline \item \code{alpha} Transparency level of \code{fill}. Not applied to \code{color}. If you want transparent lines, you can set their color as RGBA value, e.g. #FF0000A0 for partially transparent red. \item \code{group} Grouping, to draw multiple ridgelines from one dataset \item \code{linetype} Linetype of the ridgeline \item \code{size} Line thickness \item \code{point_shape}, \code{point_colour}, \code{point_size}, \code{point_fill}, \code{point_alpha}, \code{point_stroke} Aesthetics applied to points drawn in addition to ridgelines. } } \examples{ library(ggplot2) d <- data.frame(x = rep(1:5, 3), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) ggplot(d, aes(x, y, height = height, group = y)) + geom_ridgeline(fill="lightblue") } \keyword{datasets} ggridges/man/scale_vline.Rd0000644000176200001440000000301313606371763015404 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-vline.R \name{scale_vline} \alias{scale_vline_linetype} \alias{scale_vline_size_continuous} \alias{scale_vline_colour_hue} \alias{scale_vline_color_hue} \alias{scale_vline_colour_gradient} \alias{scale_vline_color_gradient} \alias{scale_vline_linetype_discrete} \alias{scale_vline_color_discrete} \alias{scale_vline_colour_discrete} \alias{scale_vline_color_continuous} \alias{scale_vline_colour_continuous} \title{Scales for vline aesthetics} \description{ These are various scales that can be applied to vline aesthetics, such as \code{vline_color}, \code{vline_size}, \code{vline_linetype}. The individual scales all have the same usage as existing standard ggplot2 scales, only the name differs. } \examples{ library(ggplot2) # default scales ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species, color = Species)) + geom_density_ridges( aes(vline_color = Species, vline_linetype = Species), alpha = .4, quantile_lines = TRUE ) + theme_ridges() # modified scales ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species, color = Species)) + geom_density_ridges( aes(vline_color = Species), alpha = .4, quantile_lines = TRUE ) + scale_fill_hue(l = 50) + scale_vline_color_hue(l = 30) + theme_ridges() } \seealso{ See \code{\link[=scale_point_color_hue]{scale_point_color_hue()}} for specific scales for point aesthetics and \code{\link[=scale_discrete_manual]{scale_discrete_manual()}} for a general discrete scale. } ggridges/man/Catalan_elections.Rd0000644000176200001440000000134313606371763016534 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.R \docType{data} \name{Catalan_elections} \alias{Catalan_elections} \title{Results from Catalan regional elections (1980-2015)} \format{A tibble with 20764 rows and 4 variables: \describe{ \item{\code{Municipality}}{} \item{\code{Year}}{} \item{\code{Option}}{The voter option; either "Indy" or "Unionist"} \item{\code{Percent}}{The percentage of the voters choosing the given option} }} \usage{ Catalan_elections } \description{ Data from Catalan regional elections for 949 municipalities, from 11 elections spanning the years 1980-2015. The data was obtained and processed from Idescat.cat by Marc Belzunces (Twitter: @marcbeldata). } \keyword{datasets} ggridges/man/position_points_jitter.Rd0000644000176200001440000000363713606436243017750 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/position.R \docType{data} \name{position_points_jitter} \alias{position_points_jitter} \alias{PositionPointsJitter} \title{Randomly jitter the points in a ridgeline plot} \usage{ position_points_jitter( width = 0, height = 0.2, yoffset = 0, adjust_vlines = FALSE, seed = NULL ) } \arguments{ \item{width}{Width for horizontal jittering. By default set to 0.} \item{height}{Height for vertical jittering, applied in both directions (up and down). By default 0.2.} \item{yoffset}{Vertical offset applied in addition to jittering.} \item{adjust_vlines}{If \code{TRUE}, adjusts vertical lines (as are drawn for quantile lines, for example) to align with the point cloud.} \item{seed}{Random seed. If set to NULL, the current random number generator is used. If set to NA, a new random random seed is generated. If set to a number, this number is used as seed for jittering only.} } \description{ This is a position adjustment specifically for \code{\link[=geom_density_ridges]{geom_density_ridges()}} and related geoms. It only jitters the points drawn by these geoms, if any. If no points are present, the plot remains unchanged. The effect is similar to \code{\link[=position_jitter]{position_jitter()}}: points are randomly shifted up and down and/or left and right. } \examples{ library(ggplot2) # default jittered points ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE, position = "points_jitter", alpha = 0.7) # simulating a rug ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE, point_shape = '|', alpha = 0.7, point_size = 2, position = position_points_jitter(width = 0.02, height = 0)) } \seealso{ Other position adjustments for ridgeline plots: \code{\link{position_points_sina}}, \code{\link{position_raincloud}} } \keyword{datasets} ggridges/man/theme_ridges.Rd0000644000176200001440000000270013606436243015554 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/theme.R \name{theme_ridges} \alias{theme_ridges} \title{A custom theme specifically for use with ridgeline plots} \usage{ theme_ridges( font_size = 14, font_family = "", line_size = 0.5, grid = TRUE, center_axis_labels = FALSE ) } \arguments{ \item{font_size}{Overall font size. Default is 14.} \item{font_family}{Default font family.} \item{line_size}{Default line size.} \item{grid}{If \code{TRUE} (default), a background grid is drawn. If \code{FALSE}, background is left empty.} \item{center_axis_labels}{If \code{TRUE}, axis labels are drawn centered. If \code{FALSE} (default), axis lables are drawn right/top-aligned.} } \value{ The theme. } \description{ This theme has some special modifications that make ridgeline plots look better, such as properly aligned y axis labels. It can draw plots with and without background grids (see examples). } \examples{ library(ggplot2) # Example with background grid ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species)) + geom_density_ridges(rel_min_height = 0.005) + scale_y_discrete(expand = c(0.01, 0)) + scale_x_continuous(expand = c(0.01, 0)) + theme_ridges() # Example without background grid ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species)) + geom_density_ridges() + scale_y_discrete(expand = c(0.01, 0)) + scale_x_continuous(expand = c(0.01, 0)) + theme_ridges(grid = FALSE) } ggridges/man/geom_density_line.Rd0000644000176200001440000000640613606373577016633 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/geom-density-line.R \docType{data} \name{geom_density_line} \alias{geom_density_line} \alias{GeomDensityLine} \title{Smoothed density estimates drawn with a ridgeline rather than area} \usage{ geom_density_line( mapping = NULL, data = NULL, stat = "density", position = "identity", ..., na.rm = FALSE, show.legend = NA, inherit.aes = TRUE ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}} or \code{\link[ggplot2:aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. All objects will be fortified to produce a data frame. See \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame}, and will be used as the layer data. A \code{function} can be created from a \code{formula} (e.g. \code{~ head(.x, 10)}).} \item{stat}{The statistical transformation to use on the data for this layer, as a string.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{colour = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes. It can also be a named logical vector to finely select the aesthetics to display.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them. This is most useful for helper functions that define both data and aesthetics and shouldn't inherit behaviour from the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} } \description{ This function is a drop-in replacement for ggplot2's \code{\link[=geom_density]{geom_density()}}. The only difference is that the geom draws a ridgeline (line with filled area underneath) rather than a polygon. } \examples{ library(ggplot2) ggplot(diamonds, aes(carat)) + geom_density_line() ggplot(diamonds, aes(carat)) + geom_density_line(adjust = 1/5) ggplot(diamonds, aes(carat)) + geom_density_line(adjust = 5) ggplot(diamonds, aes(depth, colour = cut)) + geom_density_line(alpha = 0.5) + xlim(55, 70) ggplot(diamonds, aes(depth, fill = cut, colour = cut)) + geom_density_line(alpha = 0.1) + xlim(55, 70) } \seealso{ See \code{\link[=geom_density]{geom_density()}}. } \keyword{datasets} ggridges/man/lincoln_weather.Rd0000644000176200001440000000305213606373577016305 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.R \docType{data} \name{lincoln_weather} \alias{lincoln_weather} \title{Weather in Lincoln, Nebraska in 2016.} \format{A tibble with 366 rows and 24 variables: \describe{ \item{\code{CST}}{Day of the measurement} \item{\verb{Max Temperature [F]}}{} \item{\verb{Mean Temperature [F]}}{} \item{\verb{Min Temperature [F]}}{} \item{\verb{Max Dew Point [F]}}{} \item{\verb{Mean Dew Point [F]}}{} \item{\verb{Min Dewpoint [F]}}{} \item{\verb{Max Humidity}}{} \item{\verb{Mean Humidity}}{} \item{\verb{Min Humidity}}{} \item{\verb{Max Sea Level Pressure [In]}}{} \item{\verb{Mean Sea Level Pressure [In]}}{} \item{\verb{Min Sea Level Pressure [In]}}{} \item{\verb{Max Visibility [Miles]}}{} \item{\verb{Mean Visibility [Miles]}}{} \item{\verb{Min Visibility [Miles]}}{} \item{\verb{Max Wind Speed [MPH]}}{} \item{\verb{Mean Wind Speed[MPH]}}{} \item{\verb{Max Gust Speed [MPH]}}{} \item{\code{Precipitation [In]}}{} \item{\code{CloudCover}}{} \item{\code{Events}}{Specific weather events, such as rain, snow, or fog} \item{\code{WindDir [Degrees]}}{} \item{\code{Month}}{The month in which the measurement was taken} }} \usage{ lincoln_weather } \description{ A dataset containing weather information from Lincoln, Nebraska, from 2016. Originally downloaded from Weather Underground by Austin Wehrwein, http://austinwehrwein.com/. The variables are listed below. Most are self-explanatory. Max, mean, and min measurements are calculated relative to the specific day of measurement. } \keyword{datasets} ggridges/man/reduce.Rd0000644000176200001440000000162113606371763014372 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{reduce} \alias{reduce} \title{Reduce a list to a single value by iteratively applying a binary function} \usage{ reduce(.x, .f, ..., .init) } \arguments{ \item{.x}{A list or atomic vector.} \item{.f}{A 2-argument function. The function will be passed the accumulated value as the first argument and the "next" value as the second argument.} \item{...}{Additional arguments passed on to \code{.f}.} \item{.init}{If supplied, will be used as the first value to start the accumulation, rather than using \code{x[[1]]}. This is useful if you want to ensure that \code{reduce} returns a correct value when \code{.x} is empty. If missing, and \code{x} is empty, will throw an error.} } \description{ Inspired by \code{reduce()} from the \code{purrr} package } \author{ Jonathon Love \href{mailto:jon@thon.cc}{jon@thon.cc} } ggridges/man/figures/0000755000176200001440000000000013606450274014273 5ustar liggesusersggridges/man/figures/README-diamonds-1.png0000644000176200001440000033016413606450274017677 0ustar liggesusersPNG  IHDRxa]^iCCPkCGColorSpaceGenericRGB8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|U\ @IDATx |Uյ H $! 0 ʨ:Oj>móvzjuZk铪*Dd ! 0d{ιwooY'Mh     H\     `H    To@7@@@@@      Ѝ#l@@@@@/     @@Ht@@@@      P8F@@@@H;    To@7@@@@@      Ѝ#l@@@@@/     @@Ht@@@@  CL   a em ݻw/GΝ;KQQ!6_@p* (8A_|դ^[.\(֭[z;# |ŋq222GF4}ߟ}NN媫2/gL^@h ZJf̘aӻ{nSرc5/    Zhp;Dy~]F> [^xvy5{z׹PkΛ7$/~!w]u"   ' G~s=zga.9xos    `|=e_~6X: iUUU&Ē),,luR/[}"   @b ĽDCS}!Apg7n\B?D۷OfϞ-k׮Ai .F@@@ VAZd0aS   4#u(jݻwj(A9sܹ|W^^.ݺuk>+bN{1IM[!   @ |92e|ѳhJ`ڴiQF~[:yyy2dYr޽[f̘!~[Z@@@H0J4$؆\ԩSZOm֗_~    M 6[TT$ 0?M-@%Kpz Cq5|9=7"   @|YK/E F8 6mzK?k&={l8\W74usaÆws_vve۶m`qhpnF@@@ 2#/Y~7lNӝwy&Q֡hn$ &xi     p@J4L4I^z%uC=tyx*$x#[48:    Д@ȉ'_ZM?@V\)۷o7_aUk׮:lC@@@2{sE-:t̙3'$2@oZi^gpr}7yE@@@Nmwv[n}: g϶yQS:    >i;wv" 8B 99YJJJ<Txߥֳ@@@#޽{eƌv4@k-[ȶm̰};z6EJJ}`5kgc3   G t Ç.J߾}óc|#Հ<]wڴiπ    |T?.a̙O*F=zf͚馛Nx@+w]۫ON>^ 8    _&x=O2%b1c#<8 4%~Z4NHeݲl2ٵk7 !   @ DcZZ\wu/~-F( 9rD/_nf-0}hL    `_߿|mbСdffzW_}ѣMs1 K]]%wX4o|ss@@@_&xǎ+CC*ிA,kt@@@@eyLvE\6l0A@@@MsU@ K,1sH޽:3f̰}:    ˥^*/Oc_/ܹsOy_  ޽۞իWX^^nCL   uwӦM2zh4ijժSnZUU|^9O~rkD`}~:ፖ,"   |&x׮]+cƌ9!5jjjDO9Ml=w|+ @:m6@    l&x~ٵkMJJkV7ݩS's's׹駟 8oyE<uWL'[    N _W!rrrss뮓ٳg˝wikll;=|G`ѢE6˧h?`͉ϝAk     ԩS@ ?$x5~4D܋   @x|ӧ^poذamk@S īDDSn _    LuYvC]jkktVZ%'O6v5fOoMl\8v올_, 77W222b}ѶhѢ612   D ޫZ4ymҥZ;rH@l"^{~ĉ@uuu.N^ DeE@@@2۱cG{~;ׯ<OiG&%nV)--5={zJ4@ b+W1L:    T*{_W>l3?Ζ>@=2~_KNNN! V+V[l?2;Zt@@@HX_HJJ^n?yƍL/,_|ɷhNfHKK3k;wn    &xW&;UW]%ͪ{1YzًhMNN6%`x'5:EWEE'2   S%ܜ&Lٳg/;wÇK߾}M]Oד4@kC͛Ͱx5-$vxü    ?e(ڱN:ߎ;L9k / /~[^@@@@ |]!" x=`q?hM4@@@H\ b {uOj<&| @@@Sob;F6 mhhq5\   a d Uo$???sfA@@@ ߞ"X`Ϟ=?z)OsWc*@@@HLg)ӝU#@֬YcZ޽%--̈́2w\?D     q@gJڵkm~I𦦦J~L\    @Mf N?&xu)+   @B Mf ?hu6o޼,{@@@@ $xpN&%%Iaaa'l $x[ e   Xo7!@555yf3P~~h[\ڵ gٲe@@@@ H&~Zhu뤡=~,^}@@@H ,/gu?h:gD@@@ $xsč1 f&A@@@v m'!@b=[RR"7msMMa    `HZ : ֬Yc?cN:IQQQsN/@@@ 1+Dv ***YYYΑ{ux   Yw@ [lGxz)--uƒ,@@@BoBl3D8w=zg>;$    @ _FUXXh~K:vhZ`466-DA@@@( ,"@MNN~Ⱥu낏 @@@@U$x[E oAA e"8@@@< )'!@oRR)K0@@@ ۼ"@ IUUY}NNZC@@@ j$xF dM6&ykqnntռ]|8_   ! ei ~<=~,YD?!   @H|YO ^]1ux۷܅   @HmLjb"yb$    _gv;[PP(O _~d>6C@@@ $xú "p0ϏhXݜ!={4mذA@@@$@7NLЇm޼' Ȝǜ=    Po7%!@d7nz3Haaadnw:1g:@@@ @7Lp3h$xWD   @ M֏-[\\,iii& uA@@@p 羲*@@P洠<`͉7%%EkCj^@@@@ <$xó<p'x <5vÔxК   @(Hr[YD"$x{ {yZ\ؙ@@@ ;"_dӦM&nݺz~'xΝ%|   ! d ֭[رcf g$++ˬaҥR[[k    =eE SAvNjzɒ%#   @Hh3Y D.N*8 ^ϛ7O_h    B!Tp'x|w;@@@ "@ -))$Ń֢k   Mo(PYYi tիYKUUڵˮ   Gox 7n4dffQ7ȻG   No뜸 @`rA gp:   Wox!@RY/ux^@@@ p'A u6|ihhp@@@B"@7$2@ rw7 %:tHV\9#    Hj;)NZY{    @8HcYx PUUeG K]^:   Foh @7n4CJn" P ["ԩ7oG    ~ @ a;,NCɊ+j    ^, ,-2 gN:   H5#@ 8'x;w,s0`]Ӝ9sl   [o@={. hHJJ2o9   @HYD(aXAו.ڕ͛7M?@@@@ $xD24p׃_@@@@$x} p%߽`v@@@h ޶yq5P kݶ2{]%KHuu|   q G|F85x%77AE) o]]̝;7J0,   Jo|)P__/[n5ir7%%ŗqzP3gδ}:    L7F4Y5h +$x-@@@+@7[G SAJoqq:-$d @@@ ؛3#H Zg#Gd> BA@@@ m#@ PTLéd@@@ ޞ1x(N&BAk1   q  `z;`b4{IIf͚%1i@@@@k^2JIj³k׮Z5ɫm޽z}    gqG Ȏ;Lzz7)))~xfw3fxvC@@@Hz%8 8M6R٤r+A@@@` ~-x(g!=CIJJ /"D@@@T$xO% zw7NvݵkuxC@@@*@7;˺@E-DK,_8k)    (.E/:R&B@@@ >$xά w7j*?ux}KH   D(@7B@nG lܸ.]H;#wݹsY#q   Ko*pM XL#+    }#jPD,[o9    "LV]7O0@RSS ;# B3   DUoTy*>0WD'K,L    Β@ @\AlȐ!v(`)    &D8( ޏ,!   4A1EO'xbHzzq5k;vcA@@@ 13 ;wN:0؅,fjyb793!   @D$x#f޽{СC&D쟻LÛo|+   \7@{wy<'ԩSBF@@@ 1H&澳jZ)Ϡ^E(**vѢEg+^@@@@$x}9pDGÆ 3od}A@@@|+@׷[C` - ^J4|$x7x/!   oHvk %>K*iӦIccG_C@@@_ DSGRZZj>رc,[/!   /Hr[ )yf3|׮]Cќ*pcS!p[F    .@7X>&'S=jMy;>A@@@_ v D[]ǵ'YYY9s?~    oHf+b!i&; ^Ka;III2|p󾮮Nx @@@ ^ !@82#EA@@@ ߞDQˋLzСbux냻"G@@@ $xC,Nph?Kt)//7}!   ?Hs_ $Z999Q%R!{ @@@Cob3D444Ȗ-[&wSSSq9 S1   > !mfݻGo+ziVzjY~}V@@@ )+BS=3<Ӿ{Wl   GH@ N]ogq_}:     "A( yyyQ-×͝;WvE@@@B&@7dr@ Zcּ@RR8x/K7-   \oə% ޶; ^2 m@@@-@7ŒpN𦤤 ΧKFFwޑ4RB@@@ 1H&澳jNN}\IN?%dȑ#ͥǎLCkи@@@ !6S!@n*&ݻ/̊1 v xbYfw3   Yoɸ&@?~矷}:    {7gF ^oe~߉!   @|HǝY@ $x.,,23/o0   Zo*$x322$333U&L}:    [f6dfݻxN7fСY/,LC@@@ 93"@ ӻ:% ^eԨQf}|x@   ^ GO@ Lo'x{͚}GeOJJs=    @lHƙY@ No,k_^?U8$s_]w%=z0^Mnݺ^iHII1! rȑ O   ^oැ @sH;vL4kcc m„ CIqqtAƌ#?5J]]]sKw]v#G<|K   fa]ֆ@ 444999ɓ'ˎ;\zR_%>8um&JLz4x-x   ^o뭸&}v5QǪ<| ӧO7s&''waN6E-vW_ ia:vyؚ[7o^&D@@@!@7*@ wylykfK3\|ҿf4h\pzo~~RvОyۧ    ]_FG8 8o>5kYqjj\~Z_/ZBB[ee,[U"3⋲sN?G,   Voh!;)\m'D@֚֩S'ԧ>e/lAdffYgeu2؉@@@ ;4+#G6hɂ֞up9H^^yqE],G{99~}O@@@#@7:>ewΜ9ncƌ6 hIKNqqpas'OJĉ   @`HvZpZZT;w?T5 d^//R֏~#ۧ    WFE8 TWW}EkzZUrsseРAZu9pJ>k84b),,4/]Tz8E´   $ gV@ TUU5Gkӻg}h 6}8[ZZ}ܹ}t Ҏ+   @H}p3L666 &j凝;wѣG!e3glLKM:zjG$   Lo6 ? hhXvݻLZZZ*=zx 5|XAk_pA?x&    M mڅO@ o4O.XJuYIgRTTdؾ}TTTD2\\ZN^xAl8@@@ >Ty.? ŋ[3<#{vٳg~P:YYY⬡N|ɠN   Jo`@HnݺUcB*))nݺ6;v}Xۼy󤾾{ve]&_Woq   A #vhRAwt՚h-Î1dggСCP+Vx1lL˓Ǜ9G?QLg2@@@Ao"2kD m&fձ*0rHϕǍgǜ3gsWؓ>|A X@@@ ^o"@[ z{߿8r͕>}꾶\5}ia'iݖ1}m^d&Cɏx   Jo TVVZh]d ⌭]5AxꪫlO?hr   ƑQ@G8l2hgpwi?q^EO#k;pO٘ak    @Hߎ;@Nn޼Y `رhWiXbE4Zة{Ay'>'    $xaY# &$xmff_jsȐ!ΨQ .ujIJJ2a?3k׮-x@@@ ^m !@${5u^uH:OyW_RRRp-z8EEE2~x3#G?ALg2@@@(@7ʚH`{.QWW'֭3㦧KIIsu}r!   4-@i>E h2Pҥ-??tb{%g˓={6={gsO0Ax۶mo}[@   UoXwu!`,ϰqFٿۏg}wҥ ųK_$'kaYgH    I$xO-S 6X?&xRA{-_|񮯯[oU   M mڅO@ `N] %%%4htIJzjE\^\5C-\Pz)/e @@@B)@7ʢH< ނO iiiR\\,55U bnuֵw(שS'S *-      p'xCPfee{WlbA@@@ @g{zՅOXӵagaBR7|466!4b@@@@$x} TTT۽L644ȦMw7luxޛnI233[-38_   @ M_X{رcH3$%%\RRRL\+WMJegg˗%x@֮]kA@@@ H&vB"Nzy9LVNd&ÇKUU/4cʸq0GrH~@@@/@7[@  >}:4(7(999f-Z$7}'   @HJy@ *J3S~U ^]if9:~-O[o|+    )@7!E#-[}m^gı-==]wn~wޒeBdwuu$!CĉXG&Mݻw{26    DA5bF+.v!555f}Svbuo)^}ի}\s5RRRbL=0>\{9FD@@ 0*kB  ޞ={z͛7۱\ I˗;555UNsZ8m4~ʵ(@@@Z ے#***l|^h ^7w7ux}ϗny+w߶    ($xeY'!pDo9ūMkjQFE]dY__/_lݺ5f}    @ @oJJNڦMPiiiekjaÆُ.ukb[Z:   ]ow!bG$m޽ra3MN*LnW*YYYf,X _M?@@@H`d-a'X#Y@666ՁP8ptѼ]j9_5''$yDo~O~58@@@ 8իWۘ,f-//7oL띯B:h 4i]+ӧO    VaYօ@YƮ-[΃>4,_zޅ^('͠е뮻Nܿ#h   C?(@]^1Bӷ8 ޤ$)**j"~Zsoō7(ZBeĉ_!   VaYօ@^ڵښAZyyy&\%|IZ3ƍ媫Og@@@&@o;B< *}ScVުZh֭gpOS]t뒑aH̙#礡!@@@ VK@O;v,ګӻ:SAAM&r^7m;'ySRR^zɼ7o@@@ fI9k&{2D+VHcc$ȻwaW3~   a ]d $@EE]u4&(++3>ZWO;'j7n\v=򗿴    tAAG AN L 駟nc_l'bgĉr饗ڥ)St@@@ #(Ѱk.5A=Ju$~V>l󦾾^믿~EC@@@ $xi@ hMJйsgdv'x5l:r]["v[o#G?~\yw5#  Ho6 (۷oj\66lR+Wl4%%E.чi;zh3g&KE@@ ް(A ӻԞ={zbw˗G { =|eɜ9s@@@` 5 -)ӯ^ f :Tt-Akz&ҩS'7!rˬYA@@@ p$xe֭EEEIFvm(,,:D2/Nsi&_ &y/1c#@@@Z-@T\~p'x= 9y5'E8Ȉ#K.}:"$Sa    *Ehhho.]$;;&xuxLDMRVVfЇ]qꫯx!@@@ ^n a!@[l-ͫ :VX}]lذA:d񑀖k$oyyVjy>   > Ӎ!,hZ t&xum)^}xUyڰa̗uuu2i$y>~1    #> BAرH>|:c}׾5=zNˁ|_@@@ ^q @***u^hطoIIIv0t "f)˗/0,+*kP;S&L`_ h   ~ !hV`ڵ{a.ϠXZ~`M">m1Xd[/=3r 7ȱcgt@@@ ^?1 @4i&smnnñhaOш#,ŋmΩ4?Nӟ$\r8pW@@@.@7[@ Z5kŭLjo޼yMoܱ`ȑv*Ŏ;$%%\;g}CZ @@@?2FqFXjo ?PK4 ^xAJKK뮳%b'#7o]vo : Χ ݬ,yꩧVV\)UW]%3   @8d)]@kNnCC=i۵kWҥ3E_5iosseey'O7kWyc nݺd1 k|^^?u_.;m}趏   _ob('mv6M:4wµu}L"۶m3!2 ݻw!w-iB?yIIImllb Nvv)0aOSd3:   Bo,"XtCOzնnjj ފ [U~dddر&ytgNNHK:15js…Omz[onAtM6Mƌ#AC@@@ V$xc%< ;ۧOrNjֶɓ'զ'7 p[5{-_~e`7a:6j*/{G:vh]M\0B@@ ^m !@SH;v̖} :ujj}vZ{JSO^{L'?ImhZ)ӠqwA=kNy-Ӡ    @ F{$(mKݿ/v~=eZӮzIOO7Ο?_6mԚ<2 |{ߓA#Gx?!#"   H8|TVV8af=i5b 3t.]smi}ΝK/_|EۏeN%/_.z> @@@ aH&ֳp#h"W%e߾}f\M:NDg̙s9رݫIiӦuÇ7hrםDxpYYYakW^y7gt@@@h qD>L{׮]=9(ZvDքW"\r @@@ m!@\ ~yMKKf]d3ϴ}/:&LģL 41XB8`]ˣ>*ZSN!Co~N    d!O?Z{!,R2c Z}VsmѢEk Yg%zS{'ǎpĶݞj ՚\뮻][?o&zz   @sg5@( F@@@ H&t,aٹs o߾YN7==]rssO97)[ah!/ܧ5aknDtzxҥ>\jkk'?hْo~o߾&#@@@D (;:LֈCafښ;;w?d}Z+++;܎ڄM %;8]^,*'N'|R;l1c]w%=I&%%;&Egyg?'p"A@@ ި2(D"'Gӳ'jŧvڵINm8h%'Os&nC@@ ^?!s̱U/O*;i$Sbv]yyySD3??$֦5QH&qtó>+7p lj˖-ݻ|Uz"sǎ&;we]v5[T-nE,cc&|K_e˖ÇoTӧy`[߾}gϞ5uNNdeeч񥧧KǎMi-l~xE@@ 83 R@&`34ԤbyzיSOZL8*&?e3[b27x+qI{UUZʜ𭬬{YdÆ `v:U)))Gš MkXOk[n&If{6״5&G@@,@7̻y󤦦Dw݉HN6wN5h ۏUg6;'xu5ݪ ?-Oْa hr+4 ۷˦Mdͦ|3-ͩ'uC5'5)LC@@Qo":kFOƝY-5ziǜxׯ'h۸qI?e UkEDTh$iHd.)2B.nd̕!S$"IhP) TJ*r)v{9{=}sZ{g>kY.]5n㊭ŻEl\P6m Q~L{ R)ۺ?ۡ7֭[(< ٿjrG}k޼+W.E@D@D@D@D@D + HӪ%xkԨ'щnSt(ϊ;@%{=שS'nw3b&E믿zM6mذk:Y72Ξ:u/w_Lo-\֭}A!" " " " " F@oQd0O>Aɒ%:- g@e]J*V)y tf̙3S"x~o޼ձcb9~$M/%_$( h%R]p<^z}C>?`d: ~~"SLݵ9$鿋kٞN'È?F+ k@p>c H%,D(GqD WZXYhK>˔;?Aܹ|S@&ЯL:4$ƍ kf01潹~Yep&*UdJti@t7lJ) \@ԩy/6k̅3{lF}zTJڷ@@୷d"$2VXlB tĒ%KY"֫W`;hcqOt-1cV M@0o߾>+a˖=쳮cǎNwǏz!d @!'Jl&0ggz衮TR =\g`X믿~MwtXTZ7~paG;5jwKVZMDX EW>;[_ :ԵkwMgK@;ZG*iKwi`w٦L%MrʾN?a.Um޽qMMU_(d{Wz!;v߭5"wq!9={h!" " " " "$GE@RO ,֭[7 '7{!$ E 3gδɔd6#^E<3)iv*$PD ׼ysw5x;ըQc{{-[9lٲT6]BcCH SN -]TRmYt u [|yj*1f͚ZHtInʔ)MFêy"Qiժ/܌3_|x~@6J=X/,Y29E@D@D@D@D@G@c-Aw DڵkָVApٴi_&.K/-xSm@g>|S&rW_}/τcp+Sɍ7{| (7_DZAD ^{`g?sOGwt |xǎ뛅MCR&MI&/g"'mE  6nؗ?-\}no}G0kv^5<ꨣa_" " " " " O@oCd,_~%-wy . f`'J*@2Șc=lqJ={xv 6tSrpک$m}93ܹsݼy$;Ef^zQqnvaxsE ~mgݑ,!V#v;'Ov$6)^~eߌ'x})SDxKe˖>>6櫯px;<bh̃۷jժnT 9pu"^y啠itCNFTMG] <4Z]'p-/v SO~YUAB Ҷm[ _xl2e˖mdaVw}Ћ|衇 ʕf;z!" " " " "$f9@F`T1cN>;58E th}jrXY9gw0Rd]wu]~(lӦM*}@FZC/{ŵl+oq<]6q22us-A:T[l`ȗ@j|D@{PhwOY!$+V}DRGtk.]ta殻jԨc3إ:ʗ/>lK[{@%r{de]"Wk($FY" #_)S0R|͚53!~X He}7r|/YČ3)VU;s3<ۅbQ6mҪj@ `+ 2}}m7fpha0("VPuыz[5-" " " " 9M@oN~?pn&M6(w}3H9Xݐ"l!`)ÓhMRC3vy 1cxwDvιBD ; ?,^}MԵ}; C06vz.`WK/5=1X\" 7ζURL?֌͛d=C,7 cǎ/ܾ}{[6uݏ?mȖ~Ǽ~1ǤM!׮yxXEeFA%r9\|)X=XABD@D@D@D@l;:Hc#Gt+V-dddn ,[X Zl]ॽwO}F!C|LԴ.g_w E5]~}x`?0̷=gkŲ W@igL &0x8 2x,u)eX  8?h7]tuM7ov8(D@D v1p#%2~7/"ZA fzݺuh5sپD[^Dc<š`õM!" " " " B@o CԩS'Me@ jY4Х 08qMg͚iyQ6⋽=!qE9NWDlA/ʭ5… }ܮV\9cxMd2)XB^H  IDg{I~"{D7mA S,^^bƌi+>yw}ͯϴ!s\ #`,k`pM'})L#[m <d Nx>xtҾ^%Ke=pV$zikjn@nq*dFҴkV}aÆy{o]y+4%"B^B&0-=Bn姟~rAXg q2_u@{スYP`Ga0î *D@D@D@D@ᬽAv֍+pW_}uJ۶m_|vygԌv>c[n xG\.]Rט$_['{NHҞ9 ^^Lxik6m;.}7^zMBD@Қ'o5 =0(V3C;jgjb^Sl:Vkx u¯" ʗ/m:)XW(D@D@D@D@F@o $o(豭tNHv3?1n&ɱuСX[/-ِqsO:u[ow}Xz}/&"RvO0-^g}eʱ" "N=7OD 2zKob.@@^h/-|gP,3 0l#nT@.Kg[*H .(cN]Gc29LDu sQGyN6-^L_ƎFɰƗLޖ-[BD@D `m[ V#n`( *_RLk@ 9mـr]jׯO<3g;Hod"RД,_D 6YJ$߫D0CdͼXuDcMLF\RdIgَBD@D@D@所 džzQlc/!̣5jx!_~]va\jUwwC d%cзo_j+" "<$#8`<z)d-5"Fz$L8 `){キ/0#[{ *`]2eGy" " "]$f̙A"COfgW7ٳg#G:j Y ZEݻ- ^],X(lUTqU΅{9dr5ua7xm/li ӕ"S^ڏ`e|y?zS}*D@D@rxA p%igfzy9¯15?EUɺVd wr7p L3AB SW^ۢ{'ssw={ZJWv}6l2d{g]Æ #W˺s8q?.uYvB'HvK0FΆᩧ4{޶!uw>[l?qy /cVE@D@Gb$jOWKmBM[|DcF6qgjM6 x}sOJ/@5DajDr%y!?nZ." " @@o:!n\sC@$N>dw1ny2ed–W0[oWaO?gr駟ѣGk׺Ν;gFn>sM6 ,ku 6mb 2~饗 ;Y  ͙dtM**։+V},LquaGy|4?q2=8G7|5j3f)N8u=@@ZlQX¬*̶; X{X1 :l@;6_a|y6B1 [8nzW 0jAD<СCD{]{7X11bĈ@ܥ;ٺX)cҤInk֬q7xFh m 2 ( |h>hߕn…~ $I'ZrGydeyJ*Ew >H0x?8+^m:lx/Yf . .;L'jiǂ.<މYV5F'LdQ'ul ;˼O556/uVMDdI rg tMA4&[Zjއ_^Yh獇  fF/֭v+s6ec90k nk:&Tej2O3OYvfx\fpoc X߾}c/b*".ޖeQ8m_|>|{'wўva6AC7XY0H>ւ *T(&&u|.J'>IqgQ'n ?:tJVئm_D@D@e/_>C{{Bua`fLa ̗&2m%1*;+*U}'i@Q1 LS4I:\|Faja_# yHum^x퇷p{̻ls΃eh^9i+b">#vmL kܰڴiL=ݼyswG{,_8q?袋R!gJd6q9sـ[s" !,yU/{キ-R-" " iCބy(̯|_68}3Sm_>V˒adX5^G΋|ֳԴ^tls~cmnVX0omX5Y/ o#Y\Lx3\7PX b=w ԕ,;p7pCBN: r^9]-^gJ /轈dbːK<3XYvl\>{xH_@32p;u?}Q!gW^"^8_|0a#=2sV Cq>TraYL95E@D@D@D p{;&kkghaזNMA7^irM꤄^~!xM&]$yQ⋽"6Ȫ ގx u? LѼl@%[]MO?lpl"~L4 bfeF1(x;wvѣG w~a/#d)^r%ϑױ.` 1q{'|`LC» _|ѷ'Y,įu5'l ,O[z)o߶Mm$ڵk@F\LaЩދ~d1 :pAQFydɒ-^x4]C >(rw{饗oOo6M9䓣>< 6ymܰ!R!7 ^I/uړO>鏧cǎuI4τKD@D@D@D 30ybzB4Y'b!p-V#lLRr$aPx&)֌whmyxfqإKo!*uKE`h.^d7OJcDaͰ` Y G(b@ ْvQY2dڵWOpX/y,(d*0wEy\HV_̄x Y͛~5wg,GœB6 y ;zXpoO" " " " " #k d 2MM 6GmQ#쒜4UGB .,K䉰8&N.gBL%+V&EKv=<7!XV`A s7h/<Lb?i2% ~A)p}LeEf;nqG *UYYU3 CpAM6E*D@6*F!" Y `r7μ2}$1M" "#"k,'ΎB2@fŕ3g ^ָPo1t#'l̓wz dw3'c0rH0 qDkD63<϶B^,X?dvkԨjgN@3pzgXG&#`L?] Ql#@1׈re퐑VE@D1cF"K֯e=x2 ,IŶ+ʢN:wy1P"B){=hСCo8&޽{ww=d>GXtM e ,+ZnXOƶ–L# 7Θ+"@К5kMVn'mEse <:X ;s=3?~|0_" " " " " "$QD@$Kl$Eyn8K"dK|)@$d}vwgp. >[dr!k׮AW ,pdVXѝ~> vg  w_w%[ngڊXrkgbt& 7ώ&"?ϕ*U*꺫VrqD.gr; g2Ȕ"~ ֻwo7` f^}U/tA+pX(q[@$1c[}&)~wygm2`Ϟ=|qj=zh!SN:~:% HG;c&ȏ_-/{\[kvd%n˖-nѪ|U45j8ʚ5ko>Cϓ\ <6l dFIN-ƍv,YϟfΜLߴiSV_4hu%,4Wz@k9yy@4tP7|pwUW%Kzz$DD@@z^w=mڴ"/9bo>}]I"@9N=T)S ݼy4i/BL s1I&n/ ӝM7xU#>s7w(D@D@D@D@D@D $ h" "¹{ D.]e M! nUV_} "4 ˀZju:}n J013dnԩ~dn_|;]Gb@H-/-"&NAx84i}j\͛7~NWteE'PN4 i,/_sW^ J`Ӱ= |>Ҋ~.}]tEC^r6ŋ]==։ڷ#" " " " " %#"V.]Ki!@U~bN[D )`{'>< H=ag2xB֭[,^^SO]tqtm`G_[7tM:;D@D@D@D@D@D  1h@zמAֈ2e8ZR۪-[+F^ڽ[m.N`= BerXƍsM4q߽;~j@:gAm@X+q?ە=CxwawYg+jժ&D@ G ,vuI&ۻ#F׫IexsE lٲKX!{Xdϯ^k֬__W\ Nrdqn ?k,?@F>#BD@D@D@D@D@ B@oAhi] {aޥx ~5iѢEw-Fvm7/Byo`%KK.ۥ 8ЭY&X ȋ޼h@Z2eJ.XyNНgϞ:/[|yZ" !N;VZ{r!׭[nVw?͟??X F@o4*'"&NM3xPyGydK?_~技׍5rv\:u7tPWF ;~`&D@D@D@D@D@D L@oE@Җ>c>,n F)SV(⵮ 6lذ(ki@" ݿӵh‘Knܸq]vv駟v\" " " " " "`$ " iMqD#8‘+wOXٻ(Ş ;WI!"|\x׹sgWd`suz>7|[zuL" " " " " K BLt" iH>ZE[^gn^b/V>|={vZ" %Pti׭[7zQ|[n==\od4!" " " " I@onwd &mO  ['ڶmZnG7qx-[V " '.{[8ԬY3P[m kBD@D@D@D@D 7-7UG)"6o>S='ڦ:O>O?T6mP2ۃL9=zpΟ?mٲ!2x.M)Ǣv@&?! C~}G ʕ+K/ԑR!" " " " "XG(OX1E+i@iH"uoq6lpӦMsw0`fj{-CQȱ*D@RC\{ ]vu{WА%KZ!" " " " "$fщ@V(d([c z7o޼mvW\N:b=p^{+Wom8@*UʝtIn /txg[?UZկuTd qu"{jԨLG@5]v{mb?=nС .Q<3}Q7yhOyd""7nt~aD`vrM4^n&wQG=͋6O?_r UD@D@D@D@ެ?:@lΚ5><~gKi&.N}ݮyDnvO9s3a ^ģ7 ; @zVC29zr+V^k+D@D@D@D@D@2?:j $c$,`lm+/u˔)G/]voE+\ƍ2|Ann: A~wWtn&Bb~suÙ>؝y F)" " " " F@oQdqGnW_}Gt߿`a4:4o߾}t2d782y֭4^˖,Є@J Ћm۶רZjaÇ>5j=M&D@D@D@D@D@2ތ8Mj&?ә.jΈM/m{ꩧttAX#ۓ]G|7L D+u1h_|᮹eD4!CL<${qmڴqkiӦ>_+iBD@D@D@D@D - HMӢF@O?u6l0;0g2a%@LV''cɋBnѢEq?]Vag' ~'Cn ĦH?p;s)o5kxC9ĝr)lr4!" " " " "V$PcD@ jϰr6l 2Mcorw^3MCx /o&F ܝwXOp de" GMd4?QFH5;~sׯkBD@D@D@D@D }HMsD(RL{?aOˈCenٿ&Lst^u]zdN1ܜ9sҹj4yP* {}&_uU*M8QYM@ HM9P D@@9s_x`bŊ`K*T9Am8{.{+6ol/3r]v^ jذa~2n|`&D@ҏ sZիXb_֪U+WjUo=VԄ@[3x =:;#z[XhHVTծ];Z~AkZ5c)S]veꫯF;wܣ>0̘RCE a޺ukor7f͚9JY|׎>`?`۰a܏?hU# [@Xp?Ck@b HM,OmMD ^`+2(Cyʔ)~X@G@a"0D'*]iРA^$%Aov 𧺽ڿ@xUNwEy~:j^<~K/u=TV]r%~!h@vw " H`w{;5{XMFg}~'ߖZjeծt']?Н|IOAڔuN8駟]N;5j(YMvE@Lk6_͙3͘1}>vh"GyG|Ol޼C&0@$Jkgy £{`uiϐW[ L2e˖n>LV`(_#qιs]v s9r!ٌA&YGr_+/"ȱ  G&v_wIY!$?zV״2aԆD@D%.첸2clz%R `0sd7<'0-c1nxUz/p/[l6ljݽ{wWTm@` y9߿KaÆ<kaz=3]z]lf G/_ۻ;'͟?c" @fD" "7*V@M$|26 [n\\dٳ0ђ%ryJ, }}v+r!G}F>}y*6\`cl#{{s2ւ … }U9d/,|{ao vu"qx!&wPBfϞL_SNnwLf-" E$  |.][p=`e"֮] AweSD!" " " " @@o6EdDɓ'#k $~Dgu!3{qd횰mE. vRo?׿sy4 ӦMs^xaRֳH=}Q½(PD3ʕ+KkO?NZ`nX" )'@&E˖-m2:͙3'hC p03 2F63 vZ9'1o'x‹5 r5t2猪"PlX<+_D_`a^6]wuUVuժU󅇖z\)HH$M$MmKD֬Yx >l£dz1g`D$^Rm۶/wSN)LTwAٰaC/ 2UL7-Zϕ-[ Ӻ" 9LY6BVB |lܸV _͛7ϗ`S+V=UuB)_/ (Y\9WtȷI@oxPD ȼ̨ƍ;V epk0N~p3Zڵb3٩|k֬YAĺ]w5j=zx^x_Q@ 0x|OY`ЋE+WXE VLm >懧K*fLD@D@D@D H⓫Ct'@W؇~8hf6mx'E`Mek b "L׮]/# u"rx )[~,Yg2yN/8GXd/9*`;=Cަ/ًBD@Ek Q"q {lxi&_~GGBoA adJ< ؋Ee(Sc#A9蠃|kf<4E w}3(VAMT#y~sXF0`N* +_z% [;S٤7Yl3w1cpW쵴?5PD p=,z"`AǦõͧ&82> 2}7:rXi Y{ Հ>~uFKF6Hp@8&,TG-+A3<=Xs=1ot\r#3Z!" J/^(? &[F0YL[05|ccݺu2s̨p{2~-زY뮻F}f@U "Πd5Y_~VZt*'?'O cHվ6m[4m׿ܩ}yS.WD@A`w;8(XEY/1ʃGVf@8^ _`6`p8" " " " '%"@8q^{4iRXh",qlӶm[/!o߾PxT݃>71b$ȔS@.7Xyf/KF/bL9W "S߱/6{W Z[s=O~J%|$Ǣ" " " D@o6Md[tܹe C0xj<}ȌcϾ[/`lٿ ǀb \{wX]Z[nUk@@,IJC `tlxـs˖--1m;o+ +;ӈV> ac, _ ǶE~(_km h13O!" " "$f9@Z7nhZV >HtN"⫯ ){׎,ާzʿ$Wq=~ixpe;, i-eV\99B|M5`A Gk 2b g)L w5oa=vS@ ҇z(V"X nqsv衇]N:)aW;OGu>,,XfSs6``,{KGcq/%>](-[A \oM6ۘ&.+ѳ >yk{(iMl؋_2d+6h)=H= ?ybfr: 7+2޷fzdt‹zE2d={o"d6o.v tijx \.] s9jժn!.]gKF/Y}`@D@H-j``4\40LSc`Y-- X#¯ӶmjۏvXhC{M6ڄqO+Wb 65B1`" " " ! 79\Unxjܬq3իW]uU~N;--z-N={g{6wyXGP,l>2Lx[# O> `h,]pz+IӵldC  #30YgXhW :[vyZ/ƃ]^a6xV)L5_ZAD@D H͠߷o_7p<[IU@wˢ2E|6 JG{E2^ .̜9y䑶Xu н /t*UrÇ,^ _~9s, 6." "alP9Vƍv5/b 0Q^lik#=O3.̷ۤi# 7iӦM}:ux7|3g;f͎=z{gpCY4pRW^M%d" &;t=' BזD@D@2"+5!زm=ymߖB"~&kx~` G&ۚ`(^xw.M;wv<\,ND <{,/v} ^fbݺu~P[Be&`vɐM`@{X;wNQ45jp~~ˋY_};}Pw@v K{xwE. A6/a6ׅ~Gc܋+Z{p)UMM1;h#Y!" "7])擱K63w]Nc:1ٕd/"n\pk׮ۉf 5rH!4_?PH!Z|Go{Q.7lZhZjN>d%+qmcѺѥ/0$4hY+b>}u]Fs9@1j(7q*bzժUp6l.cK=ɴ馛|`,ƻgϞAE>˗H..tߵFe˖n̘1~Ygy-V]d3k65c K.qzh@ݲkSC~*D@D Hͦ:-"GFE&͂ABD&W^bO qYf^7],֮]ޗ_~3l߾-ʚw?nxxy sx ZjMzaW\ ~$L;eSO= <طngd2/v_~Orm/뮻wy ViX[ fBiJ8/O6"qx@s!8|yyC 'rʉۙ$" " " @q+]ߗfm 6GbCe;_+ږE֜GLC~3M|]N6. oYe:Vm`@19,>HoږmYݖQ@6gw޼yd|>CW^y*!G0qv^ł d"dDop@x`0ZߧOok#gq[=7p@rȐ!)x<; Np2@XDnŭZ[8 a EoԨQl[X]$"2QyhK SdHbc}&>=0Ie$ Jr bk)D x㡔ap.yE*Ub.FVhҤIlAÆ a ,^: 4`pyeP.ꩌX>Lc=Kc)*aÆ??f[|O>6ۿ?Y$q#d '؛DYX6r-nԩǜA3|ݻwwsLF܌g8_vnvM}kC"ۭm@HyM%9 ї bew_z +ә"(X:ٿ :njN&Tdm?6bWN,E^e믷Qk2j-xo47,|ںV4ς WH'X\Dcu?δc:|9#"bgyOD lYDڲtyPCD4F2O:tmnִ AȞ=qFo#3foMBozWJb֬Ynyfrf2qgeo[/ >sܬ"tsd-΃pv'g"oTSD1po[ 8/Qb#KI?{2s̨M6&Q> IW+r :ϧ~z0X"Mʿ@ŋ^,He4x"]DܼښMǒqlΜ9j>7ϖ[zg [3>>z|T67/=7`g`zF X~ro E=GX1Z|~vIJtHLh^C_˱d,G0b!CK.>s4Yl8/gO[ԩd(S &yÆ n]Q<CLqڴi.ú] orć.U OEn8=r\'7|)6M4ɋ}fYիWYϙ%^@4$~{6 b Nᷞ GDhL=JdK#CݦM|zyD&4>G(~16wBi$x_+@^;HTA襷-6L^Ģy(T$pD2Ǟx ?s\<  n.' 6wy@ ^  gKnDo%K F6m\6w*Fς[s2J`C6ydCLJXh(RK,Z2ݙm e5;/]nظ9.ce'k;ݻb 'Ycǎ^{N8"y':d"~3; _/zQ9:B8ceɇoz U 31S:BmH׹t=3iR1c8HR.']}.+@x&5}QWc@O@AH].h#'OXͫ .tYI;$ႋ7O~p.s LxȽm"_#x|GP@,yʘ9_ /:y~›h9xD*A(t7$O̹q/>[z"p 7F<O=J>cǎv}<| o߾'::d%orz b/e޿zc%HN~" :~9'&'z[Z,15XOԕu7C)$Húxmn$s2l>a?V뺟MqU9rˠC@!Sۉ܁` B5傚_7fb'=dȹNu7#g]%姪 lx`/3gϞaO]&s%̙3Dn{\fВ@ m( C2ׯ&ΊӃ$5&/|RX~=gzB.(jxJ, '[C'/‘wx}Hv+]}y$!6"fӖ(O@\V&ZOǘ4iRP-xDT^++sO" W!D2#r&}W!IMR]E@D@D@D@D P`_&z321$|03zӡ.ԡԿB?R#3`]NDAfZpaxwumb1炉_-p~!7V Z>~xِ!C)>|pLؑD) tMSFd*\_ۆp#8}w GBD gpH}zH>/qd_ʖ-J" %"x>3g"a#HL$Y}?,^#${yOTe;k@"J:2xldH]d21 2t^МxX4pA7$,ƍlG0iΝZL#&LpkO۝ x%_bڤ(:~ybw*Q@@A"_DLc@?wB/ xfblVE@Od&,OQ`=}Dbt=h3<ت+ F{aÆٱd[nݔeXT](1 %FD@M? #{b(FF m~Μ9Qlڔea +|2z'2BD@D@D@D@D@l:jd(~;y"ިfW^iӦ + J`vr"/gOWi." " " " " ' 7X 'h7^q:n֬nk֬10D0x]o:."=ЈʉV;D@D@D@D@D@% 7__DȝR5HE`…F-Jk 2(U>}lO=T4XҥK[߾}mСVbEעk!bwmܸ1TD@D@D@D@D@D ' 9y@x7խ[7X.BXCI꒬}b_;_N֡uH:M:ˆvˆ1cX۶m>Kz}t@H$ E@JL`޼yA Pk#6m/k-@}[Ϟ=,v?͛ĉ\GD@D@D@D@D H⓯@&4S_rM^UP!0ĥ 4&M~'êA!Q&fY޽ .S#N:I9|6"xd"ilŊ;m%n/Ş! 裏On0V@ 4jȮy睨7_8 ?jd2KF|w}L"Ph[m| F,[Zje]wӫL$ 7Ϛ,YB .9í\rS[o￟%(53 `ҭ[7>|aB6l0ԩZ*" " " " " H@o4UY@87^-j׮-(srn)7@ eC탶ָqc{uZL 7Β(YHF'6Yf)0_!{|%.3S 8蠃 &^ _~+J*BNX40;XnyN!";c G}Ȇ߿1`BD@D@D@D@D@M@o |"xW6l,daժU"j׮]brʹD/Z}vM7ٟW#Eʔ)cx{r衇Zٲeݮ v9 ["[ddAD f̘/7#+o ms9[}7n!\)D@r(_/7mv=z^{-z%" " " " " q 7U@|`l2W>UTKaN:q)3 a!CXҥ]sϟovDl8jclV֯_?3znx駭]v{#`'^pf 5SD@D@D@D@D $ƃ(1+Wg}!̷xAe>6tP+W[x~饗ŋw$&fY-/vY]t O4ѣG[Fl2իWG&" " " " "xAQeK/Ѱa` xKJ0{챇uVk)SscI`w?Ǝk'|5h Ƕ .;emy_ḰH/D@D@D@D@D@^}D@҂ /ԣI&rI$a}WZݛM4Fe֭tIlٲ֮];Kn;̪Wlkܹ6d'I5ؒ%Km " " " " "JF֋il۝wi[lENʗ/oǏ/q*?GyĦO1`D@LO>7x|M[~}ֽ{wߋHfJ@`Dpo;d`+TexGŊ}'">s#K521$fYSE b̙ckٻÆ K XATğom&L~)(q6`nuZ(:D?ϟo ,kYH l:8CU@6g_m$fwD DA-'PmHg;VZւvemѢE v[^[nVݤ˩'~ a'#F6ooճ:](UCxğ+܈駟vԩc ֹsg'VVo@(7b'TL$@`A0`W͚5ҌG}Ԟ}YW)b TH,ٳg?lM>jԨawիH U͛g-[BWe˖N;z?mxdP8;HܴiS'Kʕ+絩։@d(72R Po\q0 (dJQ $f)1|n馸5}WˌZH<щ ~ɶ! %^z%=;V GּyLl{=rtCֱcGw}RJ7khx3"0xV@FѧOH>.dp qY #o_|EpPvDr?}ZO6x;ޠA]tjժ+eo K.uV`_ P''i{{:}.[[hi})gJ\:d  rTO%лwo{']>lUuyȐ!uڈ#Q("˦On'O_5{>}Xv$TJAIQٙZ֭[_3fغurKsPIfE%K K*U^o@:gEus@:gEum.v-;Ø#otE;38˶2&8q͚5LP"TQ|v=&{A9qݑ݋SO __[:WN'_; <÷ÿL|/-OxL"^$PmD ]HM3zd$@޽;~d+e"}@Ug}o߾·9^ ^ñ.af͚5 2=s"B7nަNj{PAD?^]"9ƏodZ@ٳuJj,̜1 L>Wnq!{y_zexm۶n 6ZDh*_25"/b/舿e~"mx}~:(. %D@?jժeVrn馸5m48q+c<0ygR?}t{'lPO&I'>7Ԟx7ߴ{~8-u]e˖u"o k!;?*Tp=:<(D$$𖄞s@IH- =+"fϞm۷wW]~qeq뭷q饗nUX >6`)w?ps6idW_tWd6~&Md/BO߾}֨_eSLqok2e#tY|g2%.9VX\J1bDJvVO>,|yH07r k{!77$v/V\H;^}D@" 7/*Z'" xg{nƍ矟EkҥvUW[je~z iI`v]w]}lβ`=2vW_]om@Cx=SmwvzWm"%gIJ矶dP~pyƊm >˗lLz]Z_2-?-Q% 7gV[2~[D yA~W ?=ị̂:*z2? 7uT#b>3ܗ9"K/d=Ll.c! :LV@a ~'.bmDG[LJB@oIi_. =j@pCUfMHwqYrz$}̙ʼ \ݸ@xWFG ק]ځ!=*Mo'pBTv$BGu gbCE H9V E8$sđ-bC q%`k, W,boŊ}&ė^/Rv6^>kQw2El̘1r"XLdd"2!3sWg"277hV@ H7Q' 7QH~Dhp֯_?GG'$<o馸ғY{{AK.%ٳgܳăsaժUvw;](GBe6sʦOM_@m^%7?Zj.]vִiSlx3"(xEV@fOH"sZ۶mzq?:\#Fph:문C/_/3(*UG>{ٞz)>}}c6Y3?ط(s,)f͚vAfPD(D Qg$VTe,&JT[U$BK"  -G F8|jID Πt7|S_ +Wx-[ճ^zY&MrO ^{ͦLbk׮ A&q.]wY~zKg[3I'0҂$ƍ@mK.5&}þyեF.4LDϋT)7uudHgM糣@D!Wo>?:d ڵÁ&]tqa&n)tc7|E;Su 4[lEJ ƍ[~, 7i#G *N>dcl( zyH"|ÈB/z *?%= E H@ HM \-" tG/{ĵ^k5k֌{b5MVjrK܏3ӦMˑIKkʗ/\>n[El޼yoo2SݺuO>xfRLLÃ!㡭aRKF(d2anGE4h1"zTzu+UT8g*N"B@oDN!q&WqP8M.]X!rDAfv")S:uddcs___/ᄏa᳊On^gzgْ%K\"oݻ.$7ݵkWr<+m-V@jlvkw|:/ 2}-zXx:?sε<`R;o8+Wh." " " " y'joƠC9$XBx5 zcǎ;̙3]-Yb/ٷL>J.m+Vt#`|`9VǀoKŢzȐꫯ{D q<ށU܀Zc+ܿ F8URM[mUT]Nm'X+W=b{B\\!" " " " xq HKwyKNDS>$yE.d3I(9.lS& ~{キTjbQgqgܹsQFMC?G<`ouS,7ksCV@zxs 駟vӎ;vo?ץ8ӓ݀Udl裏qUD '}k"5Ջ~b2؆u~N,J^bL̫W3xad  8S΍C{嗍̣7о*tI5czyc]vqݜdyni…tR4<= [)g}6#wVϓ"3 N4|M*Lf #pYl 5[~1Zgt=4ӕSOu. d7}t9h޼yXx<ĽE_/u~Nvrxg+9 GL2!^?{uŲˏH ŠME]w*;cƌ`v9bT#vAѣZH7nq1B4p#O&gώH=^{^W-;X)S%>#ya23ߵkvYްxd#p,8Ez"nzp 8j(yT+(4x bޯxl_v r!r^ѻdm _/`ކu" " " %% O8@}ꩧ܍%G |dK.Yxm:]n 8iovX~SN12}~$:?dѐh%+wߵ}}IڎJmIyF飏>_| |&|"kH.] }5O.={|`#qΧ!E!" !(Dv؁11s?:a 3imj\荂˄0Lƒ?mX^̷b|֛" " " M@o1?ed%0uT; ,J[޽ ' u]믻9nAo7O?t+*r Nzͯ*MZm1!LM~ Rb0k֬rԩ&"~>ӦMs!΃&z^ 2h&)ҋ~X5\x|!"c@^0 ܻ#aA"֯_&B%ʖ-$,L<,e6lτ0'z0E|r¯ ?l(gSۊ@ H-S?PbAa'x"be{nbnlϜf͚2#겞|=c\xPިQ#eIÇϷΑj#"P4sOo&L뙳9\9B]f+W湗y{BXwH~'2Z6f!BD@2oԂ+-epspQGل xAf%k<]C{Xt}u]m;|=Y -^%9?am_/ݢ]}tرX.#JO?tgoN;2aO}Νk{/\&7d6 ԄIf4Bb|@.u]y[`.#S^ÌϓwHVhd.q s? v+-Aȑ#@o}nv[z>k>du(ROz qnN5"#"Eh償#Vy|_Wz8 /a_ ~@Dqk?Ȣ!/*E\{Ѿٍr G%12G`!b/7Eb8OX_h5!7|s=lW`nN6oQnO>nsel  ,;A~*UE0E݃M7DZry,>>` x30 c_PLx?ia ^ Ɗ 9C;lLʰgԨQN8m J֊碋.r]kyhNQmR]D@D  y !Oy>mrx2B1I7 8Br@Yp^ǚ>^,ses0!Z!"P2xKHʀgt%N<t-X&\gu" l0`@EKFk~ . 'pQ;l Vp 1SтU:QQ~0W^r u9eRpCF^￿?%Y\oJN !wYfZG/پMxewNOLf ҹv{~ H),J^soG !/909˹'2EYHYKZwgeÆ )i6ȹy {9,&̙,7ׅ /s_?o6anW@qSjyMq4 x %ŊDd%™(H%_i]a!1EΒ /#%7!psaDO?r֨Q#a6yn]n|]A kwy'`w\: }Bɮ_ԏǏ믿4]vv '`e-pvGX6SND aRV]=zԩS]8G#G,RVaXD@D@ I{Dd>$GToxN/Q^es瞳ؿyMlsg]~{ϗ/П,{qߋh yt</%1 B&zG25㰍B 7N.].l~#(ߣp[;,Xm _Y[Ex."v#-ȫ wy~18kO@ѣ񝛑c98 њ5kk֬T9A>àZz?1]Q`{N-=|Ν;: K5_oׯwmG ({rCu B nɋ,| gn,&(" " " %{%h2d[zƑWIP ;ގ;J Xei9u$Ƒ=_N:,\~h(;{Vڌ7Ή&lA@o> % j^.3fnݺB*޷tqsWֺu`樣9BAa,: "Dvm~ͩb/hEϛ7o08 `{g]iꪫ -{>jD=qTP 㠵0O}1! `z!ȹ#;LX>x+x$y~3)RG@o36 |4x w/a'O>N/]vw; %w).Ǥc5Jb NDM4qޖ,. ƏvZcƌq:/B'!Lp̾}e`KQp:d,"A| 7o Fp 6!x'3;b9P୷r>׼,f7|<@Q$ >|uBZm(Op<35-gAE[)Ŧ@x϶,h@ 51(S,z{YslFp}_dߘe¦wLX>Rϰ]fPrZX_h#ɩW`Ԅ/?ӵ0^ ֠AOꫝ`ddy/7s̱)S8\.xwܒM޾}{w>6U&F3 )C<؎p(5Xbbj^KC OwA4 ꩑^Nmq7;v4*D@D@D@D@D@ &`/`% vQpiۂ EOabzzH[9yOhd:3!0c'Fþ& MYfLxvhH#1ۿW&~+ `x+|m #`3hُ4l|!؊+}(@m.,x) vr4hPFYÇK/ocN/\|.5r1x#\)2~<0((g"{2YN U6`%Bf4gE }7o_:?'>xb&e8{3@'/BBD@D@D@D@DdTH@wVc6z.3O%>^~}~s?O8qK^2m/  ./]ye2Q$,|̢.#cmF_b.9~}~so=ܰvm۶`#"N8fٕx %*3#:с@Bfs! ϖZYb7/L[1B1 Jf.|ohJdA<5# ot~Aƒ<EKA%EtC b%k/? "h5.jD==.HRz|}O*zs4bzІr3q_:ok&~;?ѹsg1boMHMS;wn GmzRV\ #9:P3%|߱DtO$|n@H>QX૮Hn=Qk"y5ԑD@Aaxd5n2cߍZĩjj#"~; "$0c$=&pvGR!Fr^@^B/ /0 ew Ǹe˖ΒQa z0(fa wmU `~K?q/LFD@D@D@D@D@2L:[ G}Dt'`./R$*RM[3Pbc v Gv輯YVW\qa/}oeErTV>_/|" " " " " "ExxV&/# 1cƸ=>|xJѦ"<Np0 b-`)5cƌ`+ڷoBpA0۴i숯ȑ#J-$~<__j." " " " " ! 72x -V[3h{'-Dx3űm۶5&d7|3.0̙3mҤI?p#pwȈV$@&MӌΊ<`K.uzs`W~En=zp${WD@D@D@D@D@D S Ȣ!SϜ-YH`޼yA%(] /tyq1}`k$n-ekЎΝ;uX|]tEn077|'-B:7v}ݸC@2 HM&mKD̙nZ0#tn_!![n˓HEz2NR>pj[;5jVaѡC Dj@ O'Q!xJs=g\r}nѢ]{vGؖ[nBzh֬˰g} ~G.o?3X"; &=3;J$o " %#G":a+SL 'lAKV2Bs`2 3}L/)Ou]g|+tv-ةDAIí@oƜ*UTJ@Iŭd+FG%vewWXv~@%fe˖.}AC lȑN_~}^ !x6n_ifguX$, Xŋ@؞!w;\rvgؠA|%RNB 6p@K7xN66nWkXwyofgkq8*TD $ٳm̘1x1ޭ䮲RK`wwx)3 8q 6̰sPď .U+W_" " " " " "$QD@frˈ. gBvnԨ >#[ڊt=GlVfF)ܟ}Y^ %'s=Ȏ'j׮S!" " " " " F@Q}D@rOnݺn]ڵ~6 sqG6mOz/b#K.za}1Sć_[CѡCmw4HSd-MO%)&AR|txHSd-MO%"3g Clz&L4!ow"ٵРA+@*UƿkCvɁGE`wY;v zԤIT6oE " " " " " )& ^D Xhذ_̊9ƍ3/$NYA܄fmC7mСC j٤(4O)A=?/RO|Ti" "5j԰Y?yƧ,?߾{WAӧOzVVk֬x-ZԷt֣G7@[2eZ(> O;\Aƌc>٫ `cǎus|g#8¶~{;m٦1p=!E@D@D@D@D@ " }&{{,kݺ붝t:`klԨQ uZz$tɮj߹sg#sYE&L[ڵ .{ϿI@ ybJTh֬ 7pmvNŽg٥^ʧ[^kժUKT"ۓO>}(6)d֩S'nZ.\7 =GmGuG 8j,JLۋ@vE"1k7?vxGŋvaƤTXh7~W7>V{Æ 6o<;w-_sAӛ6mjgy~+4nXl6|駟69v*U~Yvl,HZdѐY"ECi hȊӬF$̙3 qhԨQdEpw^zE8!0oJrak&&*5C Ncygx@?\ɶرժUˆj}-DhGB"A ,"\D1N4{Ht'ТE ;\r ƶvtzVԏ 6mڸ^2{W^/Y.[jnsl" " " " " I@of7Z"G߷+VvթSǶzȵ>kGjPt ` p[J\#y6:[ܹ(ot9Zov:udǏX^@fYK Q2zMTRV~}Ӌ_\I6x`'{ڲeһqd) YzlH'&M {QY_l֬Y9+tV@ [O^/""_>ӛ5'Ca=N:n66l&b/Yodfaz#꫶qƬa@:gGu,!uw̙oMw0D"E]  +6lB K6r{Ǎg^xuŰ=.nݵ  &تU›iYD@D@D@D@D D:>3e]EQ ||vo]nk}n5`l˗ '@/~.\ah*TW3`m۶rT^y'2w%F̪c=SOcǺY\w޽{緛ދjժ޻Lk(#23imʔ)n5LBD@D@D@D@ G@o8i+8 G JmӦM?|t/j.'>ϵ!jժN|@GZj[n.O?ub~hq_5k?& qm]F"+" " " " "`ZD ^~eꫯAy}mI\:oذի':5Ҝ:uȽD^WGtV^=7Ӊd"z[^MoްaCԩ"CrQ-$" %38ʾ؃3gGEP@6ӧ[^{5eK/j׮87܉woG+VmmNF 3X{;uFy Vd-[ϼ-)$ctee˺˗Oa{h:묳x)i2v% F&QJ1bתX1}tlAgK|{mҤand-ϿZ/hXd^Y֋]w 2$&2w!V| D/a5fl-V,jw*Ud~x~?l?X:g^l[Ts$eFQ"ȨO>q[N:["֌s9F21j(iX6 /~5/^+mY%LK.uyYQm ( (IQ9HT@P@q1**ykB.& kBDŴʂkQ̈%,DEA 柧vޞLs]USթ>=OVN'mР;#^EHNRk=՟Q7*"oj'JovSI> &6lq)N4ݑ#G fϞ{97thQ0`M/ W.iOF襛\:ƥC@ N! !xGlg >6l{7|կ_[Wo/r(MִiSy.\'f+VxVʕ+}:nݺعsg> @=w@ 鯿o:¶m}$8ZRhKҥ;餓ĉ}%z)WvmoEYz̩D@۵k%b>.sݰ_Y6nuuuɥH5R m @H!)ԙ4q'p]vjzRJqr7cƌjժxv@8իG}?EmotA@;K@ժUX+VanN/&vnv^|K6mڸ֭[VZ͚5s{B @ R![*9)ҏ5kܸq|˗/r>àMgP@B[n_~ō=r-J* g%"/H+?.]?+{n zC&BnH]a&E @ Yʅ3f yJaÆ ~I@*T.rwM7ѭZʍ;֯+[lK_~tYʕòe|DmV Y+*HsOנAmb8(\n]w_5 #@ P!@Gɷ1S`O>$sR&@^tovYK/N>d+|[hᣝjǎ^^HvZm¦M&zS)H`+%GTQkժ*XK  @0(F(6wq۸q/_,թSUZ˗ݻ[ȃ,'߻z爫eح[,B+#}[~OS"onAV:V1?ADްkRVQ/R @M77iZ'O1Q 2iz0V}vOP IE\j䟀ܕ+WĝɲVQeMBD`QO?eln}Yd;P4WJ}`C} @@< Ƴ_ҢVӧOwO=8qwkf۷;qTXos97ku#FHfeißࡵw!3){ PpzA}FÔd&PbEO"knApEׄZV~˖-l~8N1PR%/jb8YDq7y~9c= @xCZB֎zsm^^yUo%ƭ[d-_|}Y,=p Dߞ{bUd=xo6OF^xa@9p@>$I_E׳T/ PtW8Yo޼͟?߿;3V0GC  ''K6r(Jedd$$%ŠaQ/fAofWy  @@@-~Ɯd2h ЮU5kYs-'pÇ?L6 I@vU_B{@IDAT}*.RiSIKK.č5ʋMog~xIWA eHh{} DA{m8M'QW)/)كaW|lE\=ע,~7 . @@  痀,GKWY =zwvl|>f&MVT^/rjrE @O7س9tV6DS4o]zn~iTUԩСC<*q-͛e˖2*SPҖ/__l߾ݍ3~zi˄C%f5|pعs57,o k h{ժUy8|կb}ʽ 9A xӵKO=TpF͊{A4{N|Jxر^,KZhq?S3x VeqzlWƍ&L,Y' r޽gI>eW*Oz7@A'\oWts4$@ I֭cL<_ˬ¯_ÝSCc1ERY/䚂@R@Lkij)zi_>SgCw0,+ĉݕW^7 {,':F\sfsyHd~~N4&[ti};8w)Coᆄ&?ܻˆ#\Ν(?z[T(u]3Ґ |1?}.M@Jo|j٢} TFWP ڵkqyS9xTTxЗu~@w99 jzĥ'Rz:YVOou[Ӿ/M<7Yg͚? %_UYjcǎ~ 7G~$~W9RW+ PD&9s{לgNp&J9U]6mN (N]G_q;}uCnVhwuW w&1c^rw:zhwꩧc ]r~;,k?͙3NJMt˖-=#,aT>A # 8'g&BN-ԋٿkyR :^bxvmXϢ Tʕ+$n+:VJe9dѾZl5]jYXsֵoA):[;$d+Z@@@->HwNf7lnB&mꫯzޣ>Z[o5hO!CxqW", $[z*BAgǏp9.*#>3|3sO&#, p=r!>@{~5G߱cG0Z^~ًF 6 fYW]Ս_}i&T>%$ج)4nOREY6gOmcSJ}(=,'AvK麡 =Rb6UB^z=dTR%ߧ}bP 5ONAbfa7߹>3Wu{V,5&Ϝ<6m7ݜgY<$ <0 ؒ5 1\A'֧fϞ$*hBdI徢mE . ~ϴA,O5 [^AD^ +UPmIJ5^~Kmbymi}1XC,u߷h&Z=hzYe5|rT&ڹ ګT4յɘ)5Eܬ- @ x?)Qr['rW%nݺy_i-Q>VY孅c9Ʋ S  ^rL}czeTdx`#&j'8$joz&@%C@ztM7yeɒ%'t~ "1YLz(PJM( &DQ :3lm&6KDž:R͡3KXT]- jʛm 0yǘp,q ڬfϛ l@lBRMHt f;lԮ h/ 9B@}a}d}@!xh!lk늚ʊAdS}$ /Zȿ?+W)'=Q4\2 j)ЀAnqX#=ȂWA!Y #/G> *5 QGUrLr!qXrtO6WY6[jlY&HTD &I dW}~E柰fbzm yv[M ]/V{8+5^TZg/ϖi.-{o/'DZk86^/l2IMBhLڤJ|N%  %[la3l%&?DA kŊV`r5ȫpA1ϼw}y_|i!3g Qޕ(Y-[vƍO,w;wZ*يp6@HbTA"_&8fD1t^M3qNuS^i8N-0 T̴Dr-[4P-5a=,赬r3XJB -Q /l aWy-5ؾY>e[.ȹJ7]{ݯ_?9N9eLo%& 9 Ђ|2']EʑeE~& JLqNAJ A{*sz bwWLPς\ !п'_Ճȃ>n6qԈB@l`G]vgBuI[Jń_}mYc[6R+5!ZDcKâ[4?l!uJu8mR/Hsx=*ZePOyKmSʇҹ):4bn`}c},쭜&kV`_CIW 3kOmfY(o,?+a[iOVwj*Q;MR L[RK[Qy\$@@+i@T~Ye!(^|Ew9Dv&Me-_sѡ&&T-[^rQv)J|dil.wf(4qE'T´ 08:,w 7㮺*+QF7noR3w\O6ћ8FU xp9ڵs6o N{*Y-3O/x駟^ @ [Ţ2.كZnM o~lq,KU4ڄk5m&~nBRYJ+*\Zb `s#X:xK{ڝU>e$vߠ>Sy_wI'y3|VqY>>ӧ|u9d^lN;`Mv{!Yk&n҄oDe}t:Yf9Yʽ4aK+蟊&S=WV,YwqލENo=beLh#Bࠃr^xߪN'OV {K @@$+d 7QԶH Uv5_r^3bnz k`~PT^Q.!dh"4^깨dTH/k!Pd׿g3РA^}*7J~̙No8HX%\ BBK/w׍DVz7e{ Y ÇYz 0}+ a BJo)|ڴNAa+G͛c{17f 92pcR [YK+juy78w3T{. ={bR3W_}5x&lٲeܪI} @ Pj$Kh-/8 iVT^:4E}-ME+s&SjVr7h,DBڠA^ (nN&L"N;BpcwF\rz~CnwM7w :.r}.{ЪU+f͚3*GIp9r-!c x׮]kEJ01cIO MbDnH!p=Z='@# 7zA_?Q#@ {`VjFm+zJ ,ZZOh9,7dKFۧ_~94ڝ9xs"b' O?EдiS7p@7l08xtZWGvG˲,kWU??uo<4Yă܂,yU)SdMuxƂ+{N~tݔd,_: N[7Y K}>vؤ,(YzC 4%KCJd@ @! QT&_s F*XǤJ % ƥ'Ҹ]zw @~POŢF\>Zjn>U I7@ jꍒ\7ur'필[]pB- $&3%1fHb\TiC %^roHȕ,%x1Xc@+$}:ubM(rͣI3c=nb8EB @(=Ǟ3CI@_ j)@ w;tРҷv{ᇃe2 @o ԩS}g(6 b'пw>|{ge2 @o2u/̼٥KXOH@8餓\޽}y9^{G @JoI<@x:!@AIKsu[ޱc;Sܔ)S=T @ r@H@`ڵnڴi~^{Zh`/VAD@6̵oW~svoV25B @B7  K/vpU!P|y?j7j֭o:% @@Z@M@~ 3t- *V讼2˖-nРAnIP{@ @ +ެ@^|EӄLeʔ)pğ@JW_Zn++'t{'_yj@ @x d#0a„` d ]MsNwy繻;%K @ #z}J "o܌3| kܸqJP@ TP]~{AuZ7l0'@ @ x; (qX8rNX(W袋܀<~7@ @޸J?C d ' Cuۓ'OvȺ@ @ x+ (sq_kРAԃBK`^uM2t+!@ $ ${wZ D$|ͮf͚~ 1ڵ+! @ P*xK;'F ##Å^3ĭJn6׼ysr'ܧOz꒯g @ o(ҏ/_ްaCWN@!T^]wu裏{]vW_ ֑ @ PZxK<bE`A}w@(W;_U|n3t? @ RCω!ؾ}{}uʔ)uQ@ F:vעEVƍs-[t/r  @ $[9 K׿?ֺukO Фk_~*TwYf2d4h[tiX@ @ Z 'A@ּM6 *oxkomڴ)XO @@q@-N Ğƍ?_ϊ+N:žTz깛nɝ}n=ڶm~7nƎ@ @8 ']ʆbO`ĉn˖-w+W:SA@ >d۷o_7j(׫W/e]r%NO>۱cG|*MM @ "RIc xgCz@(]pnȑUV˗/w{kҤ{G֭[md @ DA7 $% /|{4@Qxs\skذaP7Æ s~m@ @( ޢX@ 7edd6tݕ--1;C Fڶm+5j(\7|pgu>}z  @ @( 5RRibMC[ou^{kӦMPWMƦ{P׮]фl6l @ _%~@Jk%K6tAޚ.Hc X ?B AfϞ'd[;SܤIۃd @ F77:lRO<d 'fdl>;]:uɪ_twW⋽ps%H @@@̇8 $ @ dѶj*_*UڵkU~WW|yU, PTwӦMx%fwC q't;\2e2 qVXb^# ~)*ԪUUV (ܿok.?/O ImT( ^xIUر#nQ`r, Pd-Zp^xtEy_aW/~ףGK/M:ܹ@ @ O&@#vЫW@ʕ+!v}OݢE3^ f͚nРANps:@ \4_b$-(\4S-[z5jpcƌa$-*<ѻo>}[xK]Knf?xw:HghHާș.rf3Tpрo:_iH Z-ݲeT!Ē3f?酕|)+cr\Ϟ=+ ߆ Ʋ]T  @p@Ղw֭~f 6IdO DYfywΜ9.mjW֭+]tadl\`X@ -`L#!P`X@(='Ntwڵk[z]!-*on޼y^q suwySw o߾J*~d @ $7j @=C>} Q@'+:( K,q_|9s[fMPk׺o>JսP>{ׯG @HhHH{Eq 6mxL V$JU\hQI}ck׮(O$SZ(! #SZ(~8hY޽.d T'Pn@ݴi/+[l ?{lxwx6wtJw`?2 @@`6@. k?O5!f{˙@ ر-XO&}]F)Sr!^{衇 *$ܗ ,x"o@ .KOP@x'] ,6AiC|u>qnނW~wYH(?_EMVZ5/!4IbV҆  @@ 0Z{:A0vpQGEV6AH%sG}ۺu7ow ~/I&uqGy;#|ڰa`_2 @@@-~Ɯ(E'Ov|A4iR@ʕ]ǎ}Te+w۶m vZs 4U<}@ @@)%B1"0jԨ6X(@(^]d;wK]vɇ3ŕf˖5j/,Z@b_nbMַo_wG:$s=ʺ$!otՄ@ s:$ ,x& z/Xq7BȋHU ŋ{^Y.[ITP*Xs˗w:urGqwн{w'_@ đq$$ԩSŕſ/<'$J@07o^0Y}s |;vzߚ5k;c@ tU@ `NJTED H$"C"K~裏_@/{WD\:4kva>vi6MIx@ ƭGA @I- >u WGA@:w};޽{{ WB d|%jOMֺukצMWL @@aࢡ08(uXm+VtguV׉ @@s=u,tvobeʕ+> Mg^_V-תU+ײeKzw#@  @ l޼]s5A5Oț=|1M}7oE_Mfyz" @x #0rHotAnI* @O@l | Vdn>qF7}tJӦMk_Y*6iUP!+y@ 'lz0*L8¨թz~Oz-7a@\pդA!$!5j8EI֯_-~%*W\$ϝ;6͚5 m)Jh&@ &״j&0L։ωVyi֭E.G@|+ <`  @ Y )Sƻdk:t noXݰaC &> ۷*/־"2 @ i &mQDRrDÚ%!Xܱc;ӝ=1˺R)@@$*jpe|Qn"{Hǯj"_~-[xWeP|y5R~>5k}թSխ[ծ]/ 6Cґo:z _%vǎ?*&ꪫ܇~ Z袋x/%A@+ W5۶m ƙ3g:ſ~Ń^Yů\Js`5Yt.aWwR|NY/,@@(?ӯ8Eh- ,X 7EƦƍsgy>a꫽Ql*HE @1'!DH$P)8x0jJBp\_f6>Tׯk3ea+&˖- ҥK=a,>ǽ]Q={jrժUxʂFlٲI;oo^|Tx"sowŠON:$wǧbSi @ H*aD_OظqcעE /,ʒT˲.WK aWVɪ,m͚Yrjڬ*h({Ypdi- r!+[WQcM'7۴i۸qw w$Vx5;v3]?CskϬDskRJZ[} CtsVĝo{x5h?~={ eyzhѧp$_x~7Џ=:.>HСCݓO>y7|?ى\h0g98 ׻woKMڵKafͅ % AKPܭ D-Y*ʂj9YCս*!Tc 4&3Sm%O k]agX+?QjڪvYO6l%򿜨+Wr 6LkJ8kZ5M*Z}tM ~[uoŀRE]c^&襂~Kzq@ȝo| t%=OcE jWBgOk;LlΝw ?|orW7<[Ѥ+ &u5\OAt"  # Raz1YjLU0K[ )JԕfVQ+\*5>+Ӣ-k{ L} [;4n^d,A׉^N,Y}7Nn6FaY"W/&k[)'Jax; G ^ÙcH@=z`zӧ"믿v?$%=3ma؅ :O2 S :?V _T `$%b8uY%JR7HȍjRKYJ _%J*ZRbO1,Wbh8H:u^n~}%AM* [ u%f\VjRj!^C]Bbǎ΢uoQ5r(>y_/1da^n ğ>xG0&Y{ y?_Ow&Lǎ }o ѭ[7)6N4 hu͂+=\L2+iz[O>T_}J=|B6zI'R4_zqh.%IuZMi}nk<!Gb,l@!%C~AW/5^eh(Qr Yu~u"\mnC٪}OQus%,<9F $T/S,oRs[" nŢ~&J0~O&Xט]QEt}/)(TE-51 `bjA"qW&?d |Ixs]w宻:nȑnȲꔗ;`/f98}Q/v۠T^iC \ HjWm~VzJ%p\Iq_ngʕ`gJlNFWionHh/Vjҕ$K3qW(Q^}mV]S8o,5]DuE#ὰױDt2FbUMTO&)'@iH up?UYgm*Y-|a {hJ&OӄsZlFQjY=H!@@:@*kLE;XXW.d a84&%i~/4^`,1QK@&]l W[ygoܹyo׵T+ fj֭V*JUTPI¬Y@'BY;+5?j@Qm̲Z.sdA/K2 c4Q!>H-՟iߚSN9ſ >)ߑGcmAJDa{5k;PL346ט\) TVh \.dj¯\i(T}ou`=&nڕmz6aZ׸u1oB@߃(J#}dmg/WzlҤI*/Xu&@G74[t뭷i}_@pM&lXhӤh?(mkM=8 &ܿtB!@@cڤ"TԬmO.RVM7?{fQQ3|\a EA8 [^Rۮr$GYD5LdɲZ}|wTSկ_5Hoy\,@  &UwQْ zqΜ9 OI-JЧd*+݂pN>Ƃ> 0 @@i3 ZkYJTjQV,b\b\X\lAVMPݼmBBLr=h]NA.M'ڞl(첮GB1륅 2 ׸k[LI/t=ȅw{Ѣjլ#k$H!I;p7xcBl۶k׮~qxРA~ɤ?F{& ϝ|XaXr  @ LJڗ^5)b" z={+W}-DZ"Xq cMK&K rI8iu|Aj./$Ȫװk fY>j 6E} lR> ڗxSi]AƟgwβ쭛-f%tRSO'xO*|С^D'@ @# !U" !,J̕k®\Xl1\f~,SeYܭuf(WTjݖJնt[ 1^r!lf%[9{AmnwUW3aC#/ݔ)S+f̘ivgyX@ @ 1^yOgY dZ0Ǘ1mBs8&\[*;mbv^MflVOVլ؝WP*Μ93᮲kQCx@wP$駟gӧ>+IDATOϞ vĉtx^|Bf͚;7Md!@ @ ;S=*vc`]%Dx)׬sbWYZj>j%*ԬZTK%jk8U^ѬxcsbR&O?y1^&峉_NA8w\#￿VjQ[r !X Cts >5ꫯZiWn76@UD3Л>l8+W`[[ngϞƟ۾l @ x^Xuƣ$*onA"e=?2{9=,Ycm,A^t]HP}G|4kb8EidqlbS³#pG_~ٷ=tz2U~d'MAt۹܂D7|ӿޚڧz7P^7}/$ަ6j(.DDZ @ ! 7Q~% Tfexmmm|OV&^RhJU :Y˚ج-|*\yCTmzk4^zۇ7zLfc_U(2¬X,R(LDiӦe9\r~*[v<2dwH)W7 V'p,e1,!0ayv纩S_QvЍMQ&M U7] @ @A@c7R-K(C1 N cٲeJ Th_ HuwƌիW2$d1]ymQ~ܳ>VZ}/d1Qos B´>Y8@ @UVeE+q4`~}Ν;ى24#4޽{N:%\jxK =' J@7pYL+ԿK@nolRMHoz(3^z#Z@fI(BQ-@r)!XmN>NNC^S@ @ @Y f @ @ !<}EM!@ @ d!  @ @o5 @ @ o,@ @ @He22CTBL`׮]n֭Aٲe]ʕmK~s;vK*Urʕ  eOL2J*iNC"}vX+_@ l޼9 {d &SoQW@ @ @!h @ @ @  &SoQW@ @ @!!d!@ @ $d- @ @ @ D7, @ @ d"LE]!@ @  ` @ @ L'Se+ w]w/)ݻ;̝|n=HO01"k.7|p4?A#8"]ܹ=n„ nѢEnӦMK.qG;x IL`7t=KԨ~gQ;Tḕ/jԨ;a3DUN  /VBM ӭ@^z{wJ[F'?/8v %p5)SdY&믿V~W]uUP'mۖ\ӦMk>]zuU9V)Rt?!-?oq+'Uڕ>>䓌Ϯɺ/We\$} Z*.>п~a͚5+C¯/nD1fPQ1n + 8}фUѩS'ߞ{qƄ(~Gu-J0S̨VK vw^zp[luFUNP (0iҤI{JxEqPĭdhVK\Y-ސ_qH4>Iˇ&۷gTZՏgk^{-O 0 ~Q*'c, @\ԩS%f 1VnZ!DO޸BaC{;3תdNW^U92C dNg~s͛7[%F;ޡ[9tЖ!ge4l0/Hb +\FI\I4UȒ 9^ʀ+suڵmO3DUӊWDU M +˗/wo|z4fNO>LA  Pr2]3bwرP'w9 ΟieO:5.QP B4tj2:s݌35awս#n#R$/dҥK}3Jo;epwSW&$1!ϵlBe5_~4 ZŘAEQN\ B O?4J|ԭ[o;wn]X3ٳggt3?t3: Ay~V0zLk`9s2QP .0ߙer !35kt#GtwGydkǸ"IarJ@][oy̯|r+V}2s8.\ HB!x.|p)go,XӦM~,ƍk׮.s/{ /Y]~}WBɲl\`AmQP Bd=ѣP-wս#n (A N9'neNhZ1ϳe (A I1CTuP> F@L UTliʕmi %0k֬* z[nw'Nq,Q(C @`7QR݀iDq6itL_>p` >b׽{M] HB!iӦ.a6X-G@*?.r7zh'pK>w{wo9%}eBQ4  ~gZnX4!4 <ۤɅ5~ǻ/S&f T_U.) a;vȳ^۷o J2@X{w_WOo7qW'??Co>}eQ4  ~gZnX4!9mb_ǘ2eo]v)ak$H!ںuk S< ;@ hv[͐Y執CN^o~6.]rGQ*U9 j9\&HW+&]j, Lz }]hT_UHB!{u ;0Vf˄^z,Bq"жm۠:s Q(Cqd D;Krv @ ! &駟:,YٱcG'$wC]F FuYre)c/_լY3XĀ>ϲ,D\uE}O]vKTv#,{*rv @ ! %ꫯ/֯_xG;hųW>1CTùa(uZ `o2_ۦMϺ@5kָy~ڱiӦQY18ILҹs,[*'K,@YD;2Tp7D]mr՟uH+˲OKsC q6ya믿VgtVU:ck$H!h׮] N6-zM>m۶ӭ[\e# =nիWwCyy4o N @ ,{G @`\$."L焲e:W\qEZŘA'؎2bG7ސJcI6lح?3*Ttϐ6p}X/O2jԨ^3'Iˇ&'1~:w9!sRc=6_1sB,-jU9q3 f\XD s¦:* ,vͺW1cTm$?9#ӇVkʕ,:|۷(߽D ?#EDFDl9E*'ד)D,{GIK9BŸ"I_N4?dΓe<~+/î!1ʌx_-,C" ˺믿>'@n&OR3/2w޻ ʗ/Ѷm OwW_edMxXbe]* EUNND0,{GI냶/ "Ÿ"}Z:kݞ y>4+2Q*'Nc2jT&T Xl5kRkڴ; xظq[pt4h2]maj>箿w\5l5kU^Չ FEqFM@@qE  "՘!rJ{̀8B @ @H&%SoQW@ @ @!!d!@ @ $d- @ @ @ D7, @ @ d"LE]!@ @  ` @ @ Lx+ @ @   @ @o2u @ @ "A @ @@2@Mޢ @ @BxC0B @ @H&[ @ @@oY@ @ @D7zB @ @@ @ @ @  &SoQW@ @ @!!d!@ @ $d- @ @ @ D7, @ @ d"LE]!@ @  ` @ @ Lx+ @ @   @ @@d,u @ @SO=&LҦM7jԨoT)sZ@ @ +ŋz7˖-!v!@ @ @ c?FC9ĝqn=Č3܂ >vkذ[l8q{ݾz:,Wreߗ_~̙kv۶ms+ƍٿץK\o_ٳ7oڷo*SLXqr @ @Gw=G %߳gO7mڴ,ڂ?A$>/ZK)=S~9hUwP@ @  68aqiӦzA{w饗k&X[FI'cۡmSY箻=3^|yc_N޽ŮWZZ{w\۶mp 1]@iP-@ @ '}'7x[n[pw矻֭[{O<,甑~7Otr rPpW8 BanE;#p!w߹c=m޼ ѣG;w׮]~ڦd,!Y]ݺuv8S=fxc1T  @ @I@w˖-o~tZשS'Wz/rtժU~qʕ+K/֬YΝ4h萄}=vgO?[mRi„ \p%[_jԨWxOvm߾]~vXlSv  @ @@; }w^/lذa}P0& G/,  @ @E-i܈#ByyyzG2Eู[,>O<9ܽ{7۷pƍ̶b@l/|E R-  @ @HڵkÇw4fܹu{]̊->kkkCD-nwΝcСCC׮]ٓ^7wr q1cߛ /;ޒ @ @@6llw_Nb:t.\lxYn]ÇCe"җ.ܭ[fΜ:wʴeeea͚5CK.]ǓWhDCK @ @ G gO} SNM?^ڰDCK @ @6 ( @ @(oK @ @6 ( @ @(oK @ @6 tn>'@ @ @UUUIHlN_Gs @ @ @@>,ѐq @ @2x3 @ @ @  Y @ @ @ S@7H @ @)q @ @2x3 @ @ @  Y @ @ @ S@7H @ @)q @ @2x3 @ @ @  Y @ @ @ S@7H @ @)q @ @2x3 @ @ @  Y @ @ @ S@7H @ @)q @ @2x3 @ @ @  Y @ @ @ S@7H @ @)q @ @2OP(cIENDB`ggridges/man/scale_cyclical.Rd0000644000176200001440000000520013606371763016052 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-cyclical.R \docType{data} \name{scale_cyclical} \alias{scale_colour_cyclical} \alias{scale_color_cyclical} \alias{scale_fill_cyclical} \alias{scale_alpha_cyclical} \alias{scale_linetype_cyclical} \alias{scale_size_cyclical} \alias{cyclical_scale} \alias{ScaleCyclical} \title{Create a discrete scale that cycles between values} \usage{ scale_colour_cyclical(..., values) scale_fill_cyclical(..., values) scale_alpha_cyclical(..., values) scale_linetype_cyclical(..., values) scale_size_cyclical(..., values) } \arguments{ \item{...}{Common discrete scale parameters: \code{name}, \code{breaks}, \code{labels}, \code{na.value}, \code{limits} and \code{guide}. See \code{\link{discrete_scale}} for more details.} \item{values}{The aesthetic values that the scale should cycle through, e.g. colors if it is a scale for the color or fill aesthetic.} } \description{ The readability of ridgeline plots can often be improved by alternating between fill colors and other aesthetics. The various cyclical scales make it easy to create plots with this feature, simply map your grouping variable to the respective aesthetic (e.g., \code{fill}) and then use \code{scale_fill_cyclical} to define the fill colors between you want to alternate. Note that the cyclical scales do not draw legends by default, because the legends will usually be wrong unless the labels are properly adjusted. To draw legends, set the \code{guide} argument to \code{"legend"}, as shown in the examples. } \examples{ library(ggplot2) # By default, scale_cyclical sets `guide = "none"`, i.e., no legend # is drawn ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("#3030D0", "#9090F0")) # However, legends can be turned on by setting `guide = "legend"` ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("#3030D0", "#9090F0"), guide = "legend", name = "Fill colors", labels = c("dark blue", "light blue")) # Cyclical scales are also available for the various other aesthetics ggplot(diamonds, aes(x = price, y = cut, fill = cut, color = cut, size = cut, alpha = cut, linetype = cut)) + geom_density_ridges(scale = 4, fill = "blue") + scale_fill_cyclical(values = c("blue", "green")) + scale_color_cyclical(values = c("black", "white")) + scale_size_cyclical(values = c(2, 1)) + scale_alpha_cyclical(values = c(0.4, 0.8)) + scale_linetype_cyclical(values = c(1, 2)) } \keyword{datasets} ggridges/man/position_points_sina.Rd0000644000176200001440000000236713606371763017405 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/position.R \docType{data} \name{position_points_sina} \alias{position_points_sina} \alias{PositionPointsSina} \title{Randomly distribute points in a ridgeline plot between baseline and ridgeline} \usage{ position_points_sina(rel_min = 0.02, rel_max = 0.98, seed = NULL) } \arguments{ \item{rel_min}{The relative minimum value at which a point can be placed.} \item{rel_max}{The relative maximum value at which a point can be placed.} \item{seed}{See \code{\link{position_points_jitter}}.} } \description{ This is a position adjustment specifically for \code{\link[=geom_density_ridges]{geom_density_ridges()}} and related geoms. It only jitters the points drawn by these geoms, if any. If no points are present, the plot remains unchanged. The effect is similar to a sina plot: Points are randomly distributed to fill the entire shaded area representing the data density. } \examples{ library(ggplot2) ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE, position = "points_sina", alpha = 0.7) } \seealso{ Other position adjustments for ridgeline plots: \code{\link{position_points_jitter}}, \code{\link{position_raincloud}} } \keyword{datasets} ggridges/man/scale_point.Rd0000644000176200001440000000350113606371763015422 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/scale-point.R \name{scale_point} \alias{scale_point_shape} \alias{scale_point_size_continuous} \alias{scale_point_colour_hue} \alias{scale_point_color_hue} \alias{scale_point_fill_hue} \alias{scale_point_colour_gradient} \alias{scale_point_color_gradient} \alias{scale_point_fill_gradient} \alias{scale_point_shape_discrete} \alias{scale_point_color_discrete} \alias{scale_point_colour_discrete} \alias{scale_point_fill_discrete} \alias{scale_point_color_continuous} \alias{scale_point_colour_continuous} \alias{scale_point_fill_continuous} \title{Scales for point aesthetics} \description{ These are various scales that can be applied to point aesthetics, such as \code{point_color}, \code{point_fill}, \code{point_size}. The individual scales all have the same usage as existing standard ggplot2 scales, only the name differs. } \examples{ library(ggplot2) # default scales ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species)) + geom_density_ridges( aes( point_color = Species, point_fill = Species, point_shape = Species ), alpha = .4, jittered_points = TRUE ) + theme_ridges() # modified scales ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species)) + geom_density_ridges( aes( point_color = Species, point_fill = Species, point_shape = Species ), alpha = .4, point_alpha = 1, jittered_points = TRUE ) + scale_fill_hue(l = 50) + scale_point_color_hue(l = 20) + scale_point_fill_hue(l = 70) + scale_discrete_manual("point_shape", values = c(21, 22, 23)) + theme_ridges() } \seealso{ See \code{\link[=scale_vline_color_hue]{scale_vline_color_hue()}} for specific scales for vline aesthetics and \code{\link[=scale_discrete_manual]{scale_discrete_manual()}} for a general discrete scale. } ggridges/man/Aus_athletes.Rd0000644000176200001440000000111513606377521015540 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/data.R \docType{data} \name{Aus_athletes} \alias{Aus_athletes} \title{Australian athletes} \format{An object of class \code{data.frame} with 202 rows and 13 columns.} \usage{ Aus_athletes } \description{ This dataset is equivalent to \code{ais} from the \code{DAAG} package. } \examples{ # none yet } \references{ Telford, R.D. and Cunningham, R.B. 1991. Sex, sport and body-size dependency of hematology in highly trained athletes. Medicine and Science in Sports and Exercise 23: 788-794. } \keyword{datasets} ggridges/man/geom_ridgeline_gradient.Rd0000644000176200001440000001032413606411213017732 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/geoms-gradient.R \docType{data} \name{geom_ridgeline_gradient} \alias{geom_ridgeline_gradient} \alias{GeomRidgelineGradient} \alias{geom_density_ridges_gradient} \alias{GeomDensityRidgesGradient} \title{Plot ridgelines and ridgeline plots with fill gradients along the x axis} \usage{ geom_ridgeline_gradient( mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, gradient_lwd = 0.5, show.legend = NA, inherit.aes = TRUE, ... ) geom_density_ridges_gradient( mapping = NULL, data = NULL, stat = "density_ridges", position = "points_sina", panel_scaling = TRUE, na.rm = TRUE, gradient_lwd = 0.5, show.legend = NA, inherit.aes = TRUE, ... ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}} or \code{\link[=aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[=ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame.}, and will be used as the layer data.} \item{stat}{The statistical transformation to use on the data for this layer, as a string.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{gradient_lwd}{A parameter to needed to remove rendering artifacts inside the rendered gradients. Should ideally be 0, but often needs to be around 0.5 or higher.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them.} \item{...}{other arguments passed on to \code{\link[=layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{color = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} \item{panel_scaling}{Argument only to \code{geom_density_ridges_gradient}. If \code{TRUE}, the default, relative scaling is calculated separately for each panel. If \code{FALSE}, relative scaling is calculated globally.} } \description{ The geoms \code{geom_ridgeline_gradient} and \code{geom_density_ridges_gradient} work just like \code{\link{geom_ridgeline}} and \code{\link{geom_density_ridges}} except that the \code{fill} aesthetic can vary along the x axis. Because filling with color gradients is fraught with issues, these geoms should be considered experimental. Don't use them unless you really need to. Note that due to limitations in R's graphics system, transparency (\code{alpha}) has to be disabled for gradient fills. } \examples{ library(ggplot2) # Example for `geom_ridgeline_gradient()` d <- data.frame( x = rep(1:5, 3) + c(rep(0, 5), rep(0.3, 5), rep(0.6, 5)), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1) ) ggplot(d, aes(x, y, height = height, group = y, fill = factor(x+y))) + geom_ridgeline_gradient() + scale_fill_viridis_d(direction = -1) + theme(legend.position = 'none') # Example for `geom_density_ridges_gradient()` ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = `Month`, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01) + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + coord_cartesian(clip = "off") + labs(title = 'Temperatures in Lincoln NE in 2016') + theme_ridges(font_size = 13, grid = TRUE) + theme(axis.title.y = element_blank()) } \keyword{datasets} ggridges/man/geom_vridgeline.Rd0000644000176200001440000001016313606373577016270 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/geomsv.R \docType{data} \name{geom_vridgeline} \alias{geom_vridgeline} \alias{GeomVRidgeline} \title{Plot a vertical ridgeline (ridgeline rotated 90 degrees)} \usage{ geom_vridgeline( mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}} or \code{\link[=aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[=ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame.}, and will be used as the layer data.} \item{stat}{The statistical transformation to use on the data for this layer, as a string.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them.} \item{...}{other arguments passed on to \code{\link[=layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{color = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} } \description{ Plots the sum of the \code{x} and \code{width} aesthetics versus \code{y}, filling the area between \code{x} and \code{x + width} with a color. Just like \code{\link[=geom_ridgeline]{geom_ridgeline()}}, but with y and x replaced. } \section{Aesthetics}{ Required aesthetics are in bold. \itemize{ \item \strong{\code{x}} \item \strong{\code{y}} \item \strong{\code{width}} Width of the ridgeline, measured from the respective \code{x} value. Assumed to be positive, though this is not required. \item \code{group} Defines the grouping. Required when the dataset contains multiple distinct ridgelines. Will typically be the same variable as is mapped to \code{x}. \item \code{scale} A scaling factor to scale the widths of the ridgelines. A value of 1 indicates that the widths are taken as is. This aesthetic can be used to convert \code{width} units into \code{x} units. \item \code{min_width} A width cutoff on the drawn ridgelines. All values that fall below this cutoff will be removed. The main purpose of this cutoff is to remove long tails right at the baseline level, but other uses are possible. The cutoff is applied before any width scaling is applied via the \code{scale} aesthetic. Default is 0, so negative values are removed. \item \code{color} Color of the ridgeline \item \code{fill} Fill color of the area under the ridgeline \item \code{alpha} Transparency level of \code{fill}. Not applied to \code{color}. If you want transparent lines, you can set their color as RGBA value, e.g. #FF0000A0 for partially transparent red. \item \code{group} Grouping, to draw multiple ridgelines from one dataset \item \code{linetype} Linetype of the ridgeline \item \code{size} Line thickness } } \examples{ library(ggplot2) d <- data.frame(y = rep(1:5, 3), x = c(rep(0, 5), rep(1, 5), rep(3, 5)), width = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) ggplot(d, aes(x, y, width = width, group = x)) + geom_vridgeline(fill="lightblue") ggplot(iris, aes(x=Species, y=Sepal.Width, width = ..density.., fill=Species)) + geom_vridgeline(stat="ydensity", trim=FALSE, alpha = 0.85, scale = 2) } \keyword{datasets} ggridges/man/stat_density_ridges.Rd0000644000176200001440000001225613606406315017170 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/stats.R \docType{data} \name{stat_density_ridges} \alias{stat_density_ridges} \alias{StatDensityRidges} \title{Stat for density ridgeline plots} \usage{ stat_density_ridges( mapping = NULL, data = NULL, geom = "density_ridges", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, bandwidth = NULL, from = NULL, to = NULL, jittered_points = FALSE, quantile_lines = FALSE, calc_ecdf = FALSE, quantiles = 4, quantile_fun = quantile, n = 512, ... ) } \arguments{ \item{mapping}{Set of aesthetic mappings created by \code{\link[=aes]{aes()}} or \code{\link[=aes_]{aes_()}}. If specified and \code{inherit.aes = TRUE} (the default), it is combined with the default mapping at the top level of the plot. You must supply \code{mapping} if there is no plot mapping.} \item{data}{The data to be displayed in this layer. There are three options: If \code{NULL}, the default, the data is inherited from the plot data as specified in the call to \code{\link[=ggplot]{ggplot()}}. A \code{data.frame}, or other object, will override the plot data. A \code{function} will be called with a single argument, the plot data. The return value must be a \code{data.frame.}, and will be used as the layer data.} \item{geom}{The geometric object to use to display the data.} \item{position}{Position adjustment, either as a string, or the result of a call to a position adjustment function.} \item{na.rm}{If \code{FALSE}, the default, missing values are removed with a warning. If \code{TRUE}, missing values are silently removed.} \item{show.legend}{logical. Should this layer be included in the legends? \code{NA}, the default, includes if any aesthetics are mapped. \code{FALSE} never includes, and \code{TRUE} always includes.} \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, rather than combining with them.} \item{bandwidth}{Bandwidth used for density calculation. If not provided, is estimated from the data.} \item{from, to}{The left and right-most points of the grid at which the density is to be estimated, as in \code{\link[=density]{density()}}. If not provided, these are estimated from the data range and the bandwidth.} \item{jittered_points}{If \code{TRUE}, carries the original point data over to the processed data frame, so that individual points can be drawn by the various ridgeline geoms. The specific position of these points is controlled by various position objects, e.g. \code{\link[=position_points_sina]{position_points_sina()}} or \code{\link[=position_raincloud]{position_raincloud()}}.} \item{quantile_lines}{If \code{TRUE}, enables the drawing of quantile lines. Overrides the \code{calc_ecdf} setting and sets it to \code{TRUE}.} \item{calc_ecdf}{If \code{TRUE}, \code{stat_density_ridges} calculates an empirical cumulative distribution function (ecdf) and returns a variable \code{ecdf} and a variable \code{quantile}. Both can be mapped onto aesthetics via \code{stat(ecdf)} and \code{stat(quantile)}, respectively.} \item{quantiles}{Sets the number of quantiles the data should be broken into. Used if either \code{calc_ecdf = TRUE} or \code{quantile_lines = TRUE}. If \code{quantiles} is an integer then the data will be cut into that many equal quantiles. If it is a vector of probabilities then the data will cut by them.} \item{quantile_fun}{Function that calculates quantiles. The function needs to accept two parameters, a vector \code{x} holding the raw data values and a vector \code{probs} providing the probabilities that define the quantiles. Default is \code{quantile}.} \item{n}{The number of equally spaced points at which the density is to be estimated. Should be a power of 2. Default is 512.} \item{...}{other arguments passed on to \code{\link[=layer]{layer()}}. These are often aesthetics, used to set an aesthetic to a fixed value, like \code{color = "red"} or \code{size = 3}. They may also be parameters to the paired geom/stat.} } \description{ This stat is the default stat used by \code{\link{geom_density_ridges}}. It is very similar to \code{\link{stat_density}}, however there are a few differences. Most importantly, the density bandwidth is chosen across the entire dataset. } \examples{ library(ggplot2) # Examples of coloring by ecdf or quantiles ggplot(iris, aes(x = Sepal.Length, y = Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = 5 ) + scale_fill_viridis_d(name = "Quintiles") + theme_ridges() ggplot(iris, aes( x = Sepal.Length, y = Species, fill = 0.5 - abs(0.5-stat(ecdf)) )) + stat_density_ridges(geom = "density_ridges_gradient", calc_ecdf = TRUE) + scale_fill_viridis_c(name = "Tail probability", direction = -1) + theme_ridges() ggplot(iris, aes( x = Sepal.Length, y = Species, fill = factor(stat(quantile)) )) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = c(0.025, 0.975) ) + scale_fill_manual( name = "Probability", values = c("#FF0000A0", "#A0A0A0A0", "#0000FFA0"), labels = c("(0, 0.025]", "(0.025, 0.975]", "(0.975, 1]") ) + theme_ridges() } \keyword{datasets} ggridges/man/ggridges.Rd0000644000176200001440000000054313606373577014725 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/ggridges.R \docType{package} \name{ggridges} \alias{ggridges} \title{Ridgeline plots with ggplot2} \description{ Please see the package vignettes for usage instructions. For a quick start, check out the examples for \code{\link[=geom_density_ridges]{geom_density_ridges()}}. } ggridges/TODO0000644000176200001440000000052013606377657012556 0ustar liggesusersThings to do ================================ - Add position_points_beeswarm() and position_points_quasirandom() - Add stat for categorical data, as described here: https://stackoverflow.com/a/47614529/4975218 - In legend drawing code, can we detect the presence of jittered points from the input data, not from the parameter setting? ggridges/DESCRIPTION0000644000176200001440000000250513606532762013567 0ustar liggesusersPackage: ggridges Type: Package Title: Ridgeline Plots in 'ggplot2' Version: 0.5.2 Authors@R: person( given = "Claus O.", family = "Wilke", role = c("aut", "cre"), email = "wilke@austin.utexas.edu", comment = c(ORCID = "0000-0002-7470-9261") ) Description: Ridgeline plots provide a convenient way of visualizing changes in distributions over time or space. This package enables the creation of such plots in 'ggplot2'. URL: https://wilkelab.org/ggridges BugReports: https://github.com/wilkelab/ggridges/issues Depends: R (>= 3.2) Imports: ggplot2 (>= 3.0.0), grid (>= 3.0.0), plyr (>= 1.8.0), scales (>= 0.4.1), withr (>= 2.1.1) License: GPL-2 | file LICENSE LazyData: true Suggests: covr, dplyr, patchwork, ggplot2movies, forcats, knitr, rmarkdown, testthat, vdiffr VignetteBuilder: knitr Collate: 'data.R' 'ggridges.R' 'geoms.R' 'geomsv.R' 'geoms-gradient.R' 'geom-density-line.R' 'position.R' 'scale-cyclical.R' 'scale-point.R' 'scale-vline.R' 'stats.R' 'theme.R' 'utils_ggplot2.R' 'utils.R' RoxygenNote: 7.0.2 NeedsCompilation: no Packaged: 2020-01-11 23:38:10 UTC; clauswilke Author: Claus O. Wilke [aut, cre] () Maintainer: Claus O. Wilke Repository: CRAN Date/Publication: 2020-01-12 06:00:18 UTC ggridges/build/0000755000176200001440000000000013606456142013153 5ustar liggesusersggridges/build/vignette.rds0000644000176200001440000000036213606456142015513 0ustar liggesusersu0E_q/+ Ƹ1ƅlR)5/Gh %q3ӹ37=B= PKР!OR9+)+nKZ$LSHJ>qv3]kGD355*-Ճ-m@x-C{?mgс^85'=lb]:pCo4'3F{z }ȗc7,?]G 1 G=t/"Nhggridges/tests/0000755000176200001440000000000013606371763013223 5ustar liggesusersggridges/tests/testthat/0000755000176200001440000000000013606532762015061 5ustar liggesusersggridges/tests/testthat/test_stat_density_ridges.R0000644000176200001440000001147613606371763022325 0ustar liggesuserscontext("stat_density_ridges") test_that("no ecdf or quantiles by default", { df <- data.frame(x = rnorm(20)) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges()) expect_false("ecdf" %in% names(out)) expect_false("quantile" %in% names(out)) }) test_that("from and to arguments work", { df <- data.frame(x = rnorm(20)) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges(from = -2, to = 2)) expect_equal(-2, min(out$x)) expect_equal(2, max(out$x)) }) test_that("calculation of ecdf and quantiles can be turned on", { df <- data.frame(x = rnorm(20)) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges(calc_ecdf = TRUE, quantiles = 5)) expect_true("ecdf" %in% names(out)) expect_true("quantile" %in% names(out)) expect_length(unique(out$quantile), 5) # either calc_ecdf = TRUE or quantile_lines = TRUE switches on quantile lines out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges(quantile_lines = TRUE, quantiles = 5)) expect_true("ecdf" %in% names(out)) expect_true("quantile" %in% names(out)) expect_length(unique(out$quantile), 5) }) test_that("jittered points and quantile lines can be turned on and off", { df <- data.frame(x = rnorm(20)) # no point or vline data type by default out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges()) expect_equal(unique(out$datatype), "ridgeline") # data points can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges(jittered_points = TRUE)) expect_setequal(out$datatype, c("ridgeline", "point")) expect_equal(out$x[out$datatype=="point"], df$x) # quantile lines can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges(quantile_lines = TRUE)) expect_setequal(out$datatype, c("ridgeline", "vline")) expect_equal(out$x[out$datatype=="vline"], unname(quantile(df$x)[2:4])) # quantile lines and data points can be turned on at once out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_density_ridges(jittered_points = TRUE, quantile_lines = TRUE)) expect_setequal(out$datatype, c("ridgeline", "vline", "point")) expect_equal(out$x[out$datatype=="point"], df$x) expect_equal(out$x[out$datatype=="vline"], unname(quantile(df$x)[2:4])) ## now repeat everything with geom_density_ridges and geom_density_ridges_gradient # no points or vlines data type by default out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges()) expect_equal(unique(out$datatype), "ridgeline") # data points can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges(jittered_points = TRUE)) expect_setequal(out$datatype, c("ridgeline", "point")) expect_equal(out$x[out$datatype=="point"], df$x) # quantile lines can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges(quantile_lines = TRUE)) expect_setequal(out$datatype, c("ridgeline", "vline")) expect_equal(out$x[out$datatype=="vline"], unname(quantile(df$x)[2:4])) # quantile lines and data points can be turned on at once out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges_gradient(jittered_points = TRUE, quantile_lines = TRUE)) expect_setequal(out$datatype, c("ridgeline", "vline", "point")) expect_equal(out$x[out$datatype=="point"], df$x) expect_equal(out$x[out$datatype=="vline"], unname(quantile(df$x)[2:4])) # no points or vlines data type by default out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges_gradient()) expect_equal(unique(out$datatype), "ridgeline") # data points can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges_gradient(jittered_points = TRUE)) expect_setequal(out$datatype, c("ridgeline", "point")) expect_equal(out$x[out$datatype=="point"], df$x) # quantile lines can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges_gradient(quantile_lines = TRUE)) expect_setequal(out$datatype, c("ridgeline", "vline")) expect_equal(out$x[out$datatype=="vline"], unname(quantile(df$x)[2:4])) # quantile lines and data points can be turned on at once out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges_gradient(jittered_points = TRUE, quantile_lines = TRUE)) expect_setequal(out$datatype, c("ridgeline", "vline", "point")) expect_equal(out$x[out$datatype=="point"], df$x) expect_equal(out$x[out$datatype=="vline"], unname(quantile(df$x)[2:4])) }) test_that("alternative quantile function can be provided", { df <- data.frame(x = rnorm(20)) # quantile lines can be turned on out <- layer_data(ggplot(df, aes(x = x, y = 0)) + geom_density_ridges(quantile_lines = TRUE, quantile_fun = mean)) expect_setequal(out$datatype, c("ridgeline", "vline")) expect_equal(out$x[out$datatype=="vline"], mean(df$x)) }) ggridges/tests/testthat/test_geom_vridgeline.R0000644000176200001440000000127013606374153021400 0ustar liggesuserscontext("geom_vridgeline") # Visual tests ------------------------------------------------------------ test_that("visual appearance of geom_vridgeline", { d <- data.frame(y = rep(1:5, 3), x = c(rep(0, 5), rep(1, 5), rep(3, 5)), width = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) p <- ggplot(d, aes(x, y, width = width, group = x)) + geom_vridgeline(fill="lightblue") vdiffr::expect_doppelganger("geom_vridgeline basic use", p) p <- ggplot(iris, aes(x=Species, y=Sepal.Width, width = ..density.., fill=Species)) + geom_vridgeline(stat="ydensity", trim=FALSE, alpha = 0.85, scale = 2) vdiffr::expect_doppelganger("geom_vridgeline using stat ydensity", p) }) ggridges/tests/testthat/test_scale_cyclical.R0000644000176200001440000000452513606374177021207 0ustar liggesuserscontext("scale_*_cyclical") test_that("basic tests", { df <- data.frame(x=sample(1:26), y=sample(1:26), letters) p <- ggplot(df, aes(x, y, label=letters, color=letters)) + geom_text() + scale_color_cyclical(values = c("#F00000", "#0000F0")) d <- layer_data(p) # make sure color pattern repeats as expected expect_equal(d$colour, rep(c("#F00000", "#0000F0"), 13)) # make sure there is no legend being generated expect_equal("guide-box" %in% ggplotGrob(p)$layout$name, FALSE) # once again, different aesthetic, different cyclical pattern, now with legend p <- ggplot(df, aes(x, y, label=letters, color=factor(x))) + geom_text() + scale_color_cyclical(values = c("#F00000", "#0000F0", "#F0F000"), guide = "legend") d <- layer_data(p) # make sure color pattern repeats as expected expect_equal(d$colour[order(d$x)], rep(c("#F00000", "#0000F0", "#F0F000"), 9)[1:26]) # make sure there is a legend expect_equal("guide-box" %in% ggplotGrob(p)$layout$name, TRUE) # test that breaks must match labels expect_error( ggplot(df, aes(x, y, label=letters, color=factor(x))) + geom_text() + scale_color_cyclical(values = c("#F00000", "#0000F0", "#F0F000"), breaks = c(1, 2, 3), labels = c("red", "blue")), "`breaks` and `labels` must have the same length") # test that legend is omitted if breaks are manually set to NULL, even when legend is switched on p <- ggplot(df, aes(x, y, label=letters, color=factor(x))) + geom_text() + scale_color_cyclical(values = c("#F00000", "#0000F0", "#F0F000"), breaks = NULL, guide = "legend") expect_equal("guide-box" %in% ggplotGrob(p)$layout$name, FALSE) }) # Visual tests ------------------------------------------------------------ test_that("visual appearance of scale_*_cyclical", { df <- data.frame(x=1:30, y=1:30) p <- ggplot(df, aes(x, y, fill = factor(x))) + geom_point(shape = 21, size = 3) + scale_fill_cyclical(values = c("#F00000", "#00F000", "#0000F0")) vdiffr::expect_doppelganger("scale_fill_cyclical red-green-blue dots, no legend", p) p <- ggplot(df, aes(x, y, color = factor(x))) + geom_point(size = 3) + scale_color_cyclical(values = c("#F00000", "#00F000", "#0000F0"), guide = "legend") vdiffr::expect_doppelganger("scale_fill_cyclical red-green-blue dots, with legend", p) }) ggridges/tests/testthat/test_geom_density_ridges.R0000644000176200001440000000143013606374115022260 0ustar liggesuserscontext("geom_density_ridges") # Visual tests ------------------------------------------------------------ test_that("geom_density_ridges draws correctly", { p <- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() vdiffr::expect_doppelganger("geom_density_ridges basic", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(rel_min_height = 0.005) vdiffr::expect_doppelganger("geom_density_ridges no trailing lines", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 3) vdiffr::expect_doppelganger("geom_density_ridges scale=3", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges2() vdiffr::expect_doppelganger("geom_density_ridges2 solid polygons", p) }) ggridges/tests/testthat/test_utils.R0000644000176200001440000000101513606371763017402 0ustar liggesusers context('utils') test_that('reduce works', { expect_equal(reduce(1:10, function(x, y) x + y), sum(1:10)) expect_equal(reduce(1:20, .init=1, function(x, y) x + y), sum(1:20)+1) expect_equal(reduce(as.list(1:20), function(x, y) x + y), sum(1:20)) expect_equal(reduce(c(T, F, T), function(x, y) x & y), FALSE) expect_equal(reduce(c('the', 'fish', 'was', 'delish'), paste), 'the fish was delish') expect_equal(reduce(list(), .init=0), 0) expect_error(reduce(list()), "`.x` is empty, and no `.init` supplied") }) ggridges/tests/testthat/Rplots.pdf0000644000176200001440000000736713606424744017054 0ustar liggesusers%PDF-1.4 %ρ\r 1 0 obj << /CreationDate (D:20200111140243) /ModDate (D:20200111140243) /Title (R Graphics Output) /Producer (R 3.6.0) /Creator (R) >> endobj 2 0 obj << /Type /Catalog /Pages 3 0 R >> endobj 7 0 obj << /Type /Page /Parent 3 0 R /Contents 8 0 R /Resources 4 0 R >> endobj 8 0 obj << /Length 22 /Filter /FlateDecode >> stream x3TR0TR( $s endstream endobj 3 0 obj << /Type /Pages /Kids [ 7 0 R ] /Count 1 /MediaBox [0 0 504 504] >> endobj 4 0 obj << /ProcSet [/PDF /Text] /Font <<>> /ExtGState << >> /ColorSpace << /sRGB 5 0 R >> >> endobj 5 0 obj [/ICCBased 6 0 R] endobj 6 0 obj << /Alternate /DeviceRGB /N 3 /Length 2596 /Filter /FlateDecode >> stream xwTSϽ7PkhRH H.*1 J"6DTpDQ2(C"QDqpId߼y͛~kg}ֺLX Xňg` lpBF|،l *?Y"1P\8=W%Oɘ4M0J"Y2Vs,[|e92<se'9`2&ctI@o|N6(.sSdl-c(2-yH_/XZ.$&\SM07#1ؙYrfYym";8980m-m(]v^DW~ emi]P`/u}q|^R,g+\Kk)/C_|Rax8t1C^7nfzDp 柇u$/ED˦L L[B@ٹЖX!@~(* {d+} G͋љς}WL$cGD2QZ4 E@@A(q`1D `'u46ptc48.`R0) @Rt CXCP%CBH@Rf[(t CQhz#0 Zl`O828.p|O×X ?:0FBx$ !i@ڐH[EE1PL ⢖V6QP>U(j MFkt,:.FW8c1L&ӎ9ƌaX: rbl1 {{{;}#tp8_\8"Ey.,X%%Gщ1-9ҀKl.oo/O$&'=JvMޞxǥ{=Vs\x ‰N柜>ucKz=s/ol|ϝ?y ^d]ps~:;/;]7|WpQoH!ɻVsnYs}ҽ~4] =>=:`;cܱ'?e~!ańD#G&}'/?^xI֓?+\wx20;5\ӯ_etWf^Qs-mw3+?~O~endstream endobj 9 0 obj << /Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [ 45/minus 96/quoteleft 144/dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron /space] >> endobj xref 0 10 0000000000 65535 f 0000000021 00000 n 0000000163 00000 n 0000000384 00000 n 0000000467 00000 n 0000000568 00000 n 0000000601 00000 n 0000000212 00000 n 0000000292 00000 n 0000003296 00000 n trailer << /Size 10 /Info 1 0 R /Root 2 0 R >> startxref 3553 %%EOF ggridges/tests/testthat/test_theme_ridges.R0000644000176200001440000000234113606374213020675 0ustar liggesuserscontext("theme_ridges") test_that("key theme_ridges settings", { # y axis labels are vertically aligned expect_equal(theme_ridges()$axis.text.y$vjust, 0) # no minor grid expect_equal(theme_ridges()$panel.grid.minor, ggplot2::element_blank()) # major grid can be switched off expect_equal(theme_ridges(grid = FALSE)$panel.grid.major, ggplot2::element_blank()) # centered axis labels can be switched on expect_equal(theme_ridges(center_axis_labels = TRUE)$axis.title.x$hjust, 0.5) expect_equal(theme_ridges(center_axis_labels = TRUE)$axis.title.y$hjust, 0.5) }) # Visual tests ------------------------------------------------------------ test_that("theme_ridges draws correctly", { d <- data.frame(x = rep(1:5, 3), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) p <- ggplot(d, aes(x, y, height = height, group = y)) + geom_ridgeline(fill="lightblue") vdiffr::expect_doppelganger("theme_ridges default", p + theme_ridges() ) vdiffr::expect_doppelganger("theme_ridges without grid", p + theme_ridges(grid = FALSE) ) vdiffr::expect_doppelganger("theme_ridges centered axis labels", p + theme_ridges(center_axis_labels = TRUE) ) }) ggridges/tests/testthat/test_geom_gradient.R0000644000176200001440000000350613606410476021050 0ustar liggesuserscontext("geom_*_gradient") # Visual tests ------------------------------------------------------------ test_that("visual appearance of gradient geoms", { df <- data.frame(x = c(1, 2, 3, 4, 5, 6), height = c(1, 2, 3, 2, 1, 2), type = c("A", "A", "B", "B", "C", "C")) p <- ggplot(df, aes(x, y = 0, height = height, group = 0, fill = type)) + geom_ridgeline_gradient() vdiffr::expect_doppelganger("geom_ridgeline_gradient basic fill pattern", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = stat(x))) + geom_density_ridges_gradient() vdiffr::expect_doppelganger("geom_density_ridges_gradient continuous fill", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = stat(ecdf))) + geom_density_ridges_gradient(calc_ecdf = TRUE) vdiffr::expect_doppelganger("geom_density_ridges_gradient ecdf fill", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = stat(quantile))) + geom_density_ridges_gradient(calc_ecdf = TRUE, quantiles = 5) vdiffr::expect_doppelganger("geom_density_ridges_gradient quintiles", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = stat(quantile))) + geom_density_ridges_gradient(calc_ecdf = TRUE, quantiles = c(0.05, 0.95)) vdiffr::expect_doppelganger("geom_density_ridges_gradient probability tails", p) p <- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = stat(quantile))) + geom_density_ridges_gradient(calc_ecdf = TRUE, quantiles = 5, quantile_lines = TRUE) vdiffr::expect_doppelganger("geom_density_ridges_gradient quantile lines match shading", p) set.seed(1234) p <- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = stat(x))) + geom_density_ridges_gradient(jittered_points = TRUE) vdiffr::expect_doppelganger("geom_density_ridges_gradient jittered points can be turned on", p) }) ggridges/tests/testthat/test_stat_binline.R0000644000176200001440000000147713606371763020731 0ustar liggesuserscontext("stat_binline") test_that("binning works", { df <- data.frame(x = sample(c(rep(1, 10), rep(2, 5), rep(3, 2), rep(6, 1)))) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_binline(binwidth = 1)) expect_equal(out$count, c(0, 0, 10, 10, 5, 5, 2, 2, 0, 0, 0, 0, 1, 1, 0, 0)) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_binline(binwidth = 1, pad = FALSE)) expect_equal(out$count, c(10, 10, 5, 5, 2, 2, 0, 0, 0, 0, 1, 1)) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_binline(binwidth = 1, draw_baseline = FALSE)) expect_equal(out$count, c(NA, 0, 10, 10, 5, 5, 2, 2, 0, NA, NA, 0, 1, 1, 0, NA)) out <- layer_data(ggplot(df, aes(x = x, y = 0)) + stat_binline(binwidth = 1, pad = FALSE, draw_baseline = FALSE)) expect_equal(out$count, c(10, 10, 5, 5, 2, 2, 0, NA, NA, 0, 1, 1)) }) ggridges/tests/figs/0000755000176200001440000000000013606374237014152 5ustar liggesusersggridges/tests/figs/theme-ridges/0000755000176200001440000000000013606375354016530 5ustar liggesusersggridges/tests/figs/theme-ridges/theme-ridges-default.svg0000644000176200001440000002016313606375342023247 0ustar liggesusers 0 2 4 6 8 1 2 3 4 5 x y theme_ridges default ggridges/tests/figs/theme-ridges/theme-ridges-centered-axis-labels.svg0000644000176200001440000002020113606375354025612 0ustar liggesusers 0 2 4 6 8 1 2 3 4 5 x y theme_ridges centered axis labels ggridges/tests/figs/theme-ridges/theme-ridges-without-grid.svg0000644000176200001440000001302013606375127024244 0ustar liggesusers 0 2 4 6 8 1 2 3 4 5 x y theme_ridges without grid ggridges/tests/figs/deps.txt0000644000176200001440000000010313606425050015626 0ustar liggesusers- vdiffr-svg-engine: 1.0 - vdiffr: 0.3.0 - freetypeharfbuzz: 0.2.5 ggridges/tests/figs/geom-density-ridges/0000755000176200001440000000000013606374367020035 5ustar liggesusersggridges/tests/figs/geom-density-ridges/geom-density-ridges-no-trailing-lines.svg0000644000176200001440000013326513606374333027771 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species geom_density_ridges no trailing lines ggridges/tests/figs/geom-density-ridges/geom-density-ridges-basic.svg0000644000176200001440000021062013606374323025505 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species geom_density_ridges basic ggridges/tests/figs/geom-density-ridges/geom-density-ridges-scale-3.svg0000644000176200001440000021070613606374360025661 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species geom_density_ridges scale=3 ggridges/tests/figs/geom-density-ridges/geom-density-ridges2-solid-polygons.svg0000644000176200001440000013625513606374367027513 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species geom_density_ridges2 solid polygons ggridges/tests/figs/geom-gradient/0000755000176200001440000000000013606410621016660 5ustar liggesusersggridges/tests/figs/geom-gradient/geom-ridgeline-gradient-basic-fill-pattern.svg0000644000176200001440000001654413606374626027571 0ustar liggesusers 0 1 2 3 2 4 6 x y type A B C geom_ridgeline_gradient basic fill pattern ggridges/tests/figs/geom-gradient/geom-density-ridges-gradient-continuous-fill.svg0000644000176200001440000065765113606425042030232 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species 4 5 6 7 8 x geom_density_ridges_gradient continuous fill ggridges/tests/figs/geom-gradient/geom-density-ridges-gradient-quantile-lines-match-shading.svg0000644000176200001440000023023213606410555032520 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species quantile 1 2 3 4 5 geom_density_ridges_gradient quantile lines match shading ggridges/tests/figs/geom-gradient/geom-density-ridges-gradient-ecdf-fill.svg0000644000176200001440000053230013606425045026707 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species 0.00 0.25 0.50 0.75 1.00 ecdf geom_density_ridges_gradient ecdf fill ggridges/tests/figs/geom-gradient/geom-density-ridges-gradient-jittered-points-can-be-turned-on.svg0000644000176200001440000073247413606425050033254 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species 4 5 6 7 8 x geom_density_ridges_gradient jittered points can be turned on ggridges/tests/figs/geom-gradient/geom-density-ridges-gradient-probability-tails.svg0000644000176200001440000021660213606374757030535 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species quantile 1 2 3 geom_density_ridges_gradient probability tails ggridges/tests/figs/geom-gradient/geom-density-ridges-gradient-quintiles.svg0000644000176200001440000022267213606374744027120 0ustar liggesusers setosa versicolor virginica 4 5 6 7 8 Sepal.Length Species quantile 1 2 3 4 5 geom_density_ridges_gradient quintiles ggridges/tests/figs/geom-vridgeline/0000755000176200001440000000000013606375021017217 5ustar liggesusersggridges/tests/figs/geom-vridgeline/geom-vridgeline-using-stat-ydensity.svg0000644000176200001440000021252713606375021026770 0ustar liggesusers 2 3 4 setosa versicolor virginica Species Sepal.Width Species setosa versicolor virginica geom_vridgeline using stat ydensity ggridges/tests/figs/geom-vridgeline/geom-vridgeline-basic-use.svg0000644000176200001440000001575113606375015024702 0ustar liggesusers 1 2 3 4 5 0 2 4 6 8 x y geom_vridgeline basic use ggridges/tests/figs/scale-cyclical/0000755000176200001440000000000013606375052017016 5ustar liggesusersggridges/tests/figs/scale-cyclical/scale-fill-cyclical-red-green-blue-dots-with-legend.svg0000644000176200001440000002723013606375052031306 0ustar liggesusers 0 10 20 30 0 10 20 30 x y factor(x) 1 2 3 scale_fill_cyclical red-green-blue dots, with legend ggridges/tests/figs/scale-cyclical/scale-fill-cyclical-red-green-blue-dots-no-legend.svg0000644000176200001440000002232113606375034030743 0ustar liggesusers 0 10 20 30 0 10 20 30 x y scale_fill_cyclical red-green-blue dots, no legend ggridges/tests/testthat.R0000644000176200001440000000007413606371763015207 0ustar liggesuserslibrary(testthat) library(ggridges) test_check("ggridges") ggridges/vignettes/0000755000176200001440000000000013606456142014064 5ustar liggesusersggridges/vignettes/introduction.Rmd0000644000176200001440000005004013606436215017247 0ustar liggesusers--- title: "Introduction to ggridges" author: "Claus O. Wilke" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: fig_width: 6 fig_height: 4 vignette: > %\VignetteIndexEntry{Introduction to ggridges} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- Ridgeline plots are partially overlapping line plots that create the impression of a mountain range. They can be quite useful for visualizing changes in distributions over time or space. ## Geoms The **ggridges** package provides two main geoms, `geom_ridgeline` and `geom_density_ridges`. The former takes height values directly to draw ridgelines, and the latter first estimates data densities and then draws those using ridgelines. ### Ridgelines The geom `geom_ridgeline` can be used to draw lines with a filled area underneath. ```{r warning = FALSE, message = FALSE} library(ggplot2) library(ggridges) data <- data.frame(x = 1:5, y = rep(1, 5), height = c(0, 1, 3, 4, 2)) ggplot(data, aes(x, y, height = height)) + geom_ridgeline() ``` Negative heights are allowed, but are cut off unless the `min_height` parameter is set negative as well. ```{r message = FALSE, fig.width=9, fig.height=3} library(patchwork) # for side-by-side plotting data <- data.frame(x = 1:5, y = rep(1, 5), height = c(0, 1, -1, 3, 2)) plot_base <- ggplot(data, aes(x, y, height = height)) plot_base + geom_ridgeline() | plot_base + geom_ridgeline(min_height = -2) ``` Multiple ridgelines can be drawn at the same time. They will be ordered such that the ones drawn higher up are in the background. When drawing multiple ridgelines at once, the `group` aesthetic must be specified so that the geom knows which parts of the data belong to which ridgeline. ```{r message = FALSE} d <- data.frame( x = rep(1:5, 3), y = c(rep(0, 5), rep(1, 5), rep(2, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1) ) ggplot(d, aes(x, y, height = height, group = y)) + geom_ridgeline(fill = "lightblue") ``` It is also possible to draw ridgelines with `geom_density_ridges` if we set `stat = "identity"`. In this case, the heights are automatically scaled such that the highest ridgeline just touches the one above at `scale = 1`. ```{r message = FALSE} ggplot(d, aes(x, y, height = height, group = y)) + geom_density_ridges(stat = "identity", scale = 1) ``` ### Density ridgeline plots The geom `geom_density_ridges` calculates density estimates from the provided data and then plots those, using the ridgeline visualization. The `height` aesthetic does not need to be specified in this case. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() ``` There is also `geom_density_ridges2`, which is identical to `geom_density_ridges` except it uses closed polygons instead of ridgelines for drawing. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges2() ``` The grouping aesthetic does not need to be provided if a categorical variable is mapped onto the y axis, but it does need to be provided if the variable is numerical. ```{r message=FALSE} # modified dataset that represents species as a number iris_num <- transform(iris, Species_num = as.numeric(Species)) # does not work, causes error # ggplot(iris_num, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() # works ggplot(iris_num, aes(x = Sepal.Length, y = Species_num, group = Species_num)) + geom_density_ridges() ``` Trailing tails can be cut off using the `rel_min_height` aesthetic. This aesthetic sets a percent cutoff relative to the highest point of any of the density curves. A value of 0.01 usually works well, but you may have to modify this parameter for different datasets. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(rel_min_height = 0.01) ``` The extent to which the different densities overlap can be controlled with the `scale` parameter. A setting of `scale=1` means the tallest density curve just touches the baseline of the next higher one. Smaller values create a separation between the curves, and larger values create more overlap. ```{r message=FALSE} # scale = 0.9, not quite touching ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 0.9) # scale = 1, exactly touching ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 1) # scale = 5, substantial overlap ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 5) ``` The scaling is calculated separately per panel, so if we facet-wrap by species each density curve exactly touches the next higher baseline. (This can be disabled by setting `panel_scaling = FALSE`.) ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 1) + facet_wrap(~Species) ``` ### Varying fill colors along the x axis Sometimes we would like to have the area under a ridgeline not filled with a single solid color but rather with colors that vary in some form along the x axis. This effect can be achieved with the geoms `geom_ridgeline_gradient` and `geom_density_ridges_gradient`. Both geoms work just like `geom_ridgeline` and `geom_density_ridges`, except that they allow for varying fill colors. **However,** they do not allow for alpha transparency in the fill. For technical reasons, we can have changing fill colors or transparency but not both. Here is a simple example of changing fill colors with `geom_ridgeline_gradient`: ```{r message = FALSE} d <- data.frame( x = rep(1:5, 3) + c(rep(0, 5), rep(0.3, 5), rep(0.6, 5)), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) ggplot(d, aes(x, y, height = height, group = y, fill = factor(x+y))) + geom_ridgeline_gradient() + scale_fill_viridis_d(direction = -1, guide = "none") ``` And here is an example using `geom_density_ridges_gradient`. Note that we need to map the calculated x value (`stat(x)`) onto the fill aesthetic, not the original temperature variable. This is the case because `geom_density_ridges_gradient` calls `stat_density_ridges` (described in the next section) which calculates new x values as part of its density calculation. ```{r message = FALSE} ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = Month, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + labs(title = 'Temperatures in Lincoln NE in 2016') ``` ## Stats The ggridges package provides a stat `stat_density_ridges` that replaces `stat_density` in the context of ridgeline plots. In addition to setting up the proper `height` for `geom_density_ridges`, this stat has a number of additional features that may be useful. ### Quantile lines and coloring by quantiles or probabilities By setting the option `quantile_lines = TRUE`, we can make `stat_density_ridges` calculate the position of lines indicating quantiles. By default, three lines are drawn, corresponding to the first, second, and third quartile: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE) ``` We can change the number of quantiles by specifying it via the `quantiles` option. Note that `quantiles = 2` implies one line (the median) at the boundary between the two quantiles. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE, quantiles = 2) ``` We can also specify quantiles by cut points rather than number. E.g., we can indicate the 2.5% and 97.5% tails. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE, quantiles = c(0.025, 0.975), alpha = 0.7) ``` Using the geom `geom_density_ridges_gradient` we can also color by quantile, via the calculated `stat(quantile)` aesthetic. Note that this aesthetic is only calculated if `calc_ecdf = TRUE`. ```{r message = FALSE} ggplot(iris, aes(x=Sepal.Length, y=Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = 4, quantile_lines = TRUE ) + scale_fill_viridis_d(name = "Quartiles") ``` We can use the same approach to highlight the tails of the distributions. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = c(0.025, 0.975) ) + scale_fill_manual( name = "Probability", values = c("#FF0000A0", "#A0A0A0A0", "#0000FFA0"), labels = c("(0, 0.025]", "(0.025, 0.975]", "(0.975, 1]") ) ``` Finally, when `calc_ecdf = TRUE`, we also have access to a calculated aesthetic `stat(ecdf)`, which represents the empirical cumulative density function for the distribution. This allows us to map the probabilities directly onto color. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = 0.5 - abs(0.5 - stat(ecdf)))) + stat_density_ridges(geom = "density_ridges_gradient", calc_ecdf = TRUE) + scale_fill_viridis_c(name = "Tail probability", direction = -1) ``` ### Jittering points The stat `stat_density_ridges` also provides the option to visualize the original data points from which the distributions are generated. This can be done by setting `jittered_points = TRUE`, either in `stat_density_ridges` or in `geom_density_ridges`: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE) ``` Where the points are shown can be controlled with position options, e.g. "raincloud" for the raincloud effect: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, position = "raincloud", alpha = 0.7, scale = 0.9 ) ``` We can also simulate a rug: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, position = position_points_jitter(width = 0.05, height = 0), point_shape = '|', point_size = 3, point_alpha = 1, alpha = 0.7, ) ``` Note that we are using `position_points_jitter()` here, not `position_jitter()`. We do this because `position_points_jitter()` knows to jitter only the points in a ridgeline plot, without touching the density lines. Styling the jittered points is a bit tricky but is possible with special scales provided by ggridges. First, there is `scale_discrete_manual()` which can be used to make arbitrary discrete scales for arbitrary aesthetics. We use it in the next example to style the point shapes. Second, there are various point aesthetic scales, such as `scale_point_color_hue()`. See the reference documentation for these scales for more details. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = Species)) + geom_density_ridges( aes(point_color = Species, point_fill = Species, point_shape = Species), alpha = .2, point_alpha = 1, jittered_points = TRUE ) + scale_point_color_hue(l = 40) + scale_discrete_manual(aesthetics = "point_shape", values = c(21, 22, 23)) ``` All common aesthetics for points can be applied to the jittered points. However, the aesthetic names start with `point_`. In the next example, we have mapped an additional variable onto the size of the points. ```{r message = FALSE, fig.width = 6, fig.height = 6} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = Species)) + geom_density_ridges( aes(point_shape = Species, point_fill = Species, point_size = Petal.Length), alpha = .2, point_alpha = 1, jittered_points = TRUE ) + scale_point_color_hue(l = 40) + scale_point_size_continuous(range = c(0.5, 4)) + scale_discrete_manual(aesthetics = "point_shape", values = c(21, 22, 23)) ``` Similarly, we have aesthetics for the vertical lines, named `vline_`. And the vertical lines can also be shifted so they are aligned with the jittered points. This allows us to generate figures such as the following: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, quantile_lines = TRUE, scale = 0.9, alpha = 0.7, vline_size = 1, vline_color = "red", point_size = 0.4, point_alpha = 1, position = position_raincloud(adjust_vlines = TRUE) ) ``` ### Using alternative stats The stat `stat_density_ridges` may not always do exactly what you want it to do. If this is the case, you can use other stats that may be better for your respective application. First, `stat_density_ridges` estimates the data range and bandwidth for the density estimation from the entire data at once, rather than from each individual group of data. This choice makes ridgeline plots look more uniform, but the density estimates can in some cases look quite different from what you would get from `geom_density` or `stat_density`. This problem can be remedied by using `stat_density` with `geom_density_ridges`. This works just fine, we just need to make sure that we map the calculated density onto the `height` aesthetic. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, height = stat(density))) + geom_density_ridges(stat = "density") ``` Second, there may be scenarios in which you don't want `geom_density_ridges` to do any density estimation, for example because you have done so already yourself. In this case, you can use `stat_identity`. The benefit of using `geom_density_ridges` with `stat_identiy` over using `geom_ridgeline` directly is that `geom_density_ridges` provides automatic scaling. As an example, assume we have calculated density curves for the `Sepal.Length` column in the `iris` dataset: ```{r message=FALSE} library(dplyr) iris_densities <- iris %>% group_by(Species) %>% group_modify(~ ggplot2:::compute_density(.x$Sepal.Length, NULL)) %>% rename(Sepal.Length = x) iris_densities ``` We can plot these as follows: ```{r message=FALSE} ggplot(iris_densities, aes(x = Sepal.Length, y = Species, height = density)) + geom_density_ridges(stat = "identity") ``` Notice how this plot looks different from the one generated using `stat = "density"`, even though the density computation was exactly the same: (i) The density curves extend all the way to zero. (ii) There is no horizontal line extending all the way to the limits of the x axis. Finally, if you prefer histograms to density plots, you can also use `stat_binline`. Note that overlapping histograms can look strange, so this option is probably best used with a `scale` parameter < 1. The option `draw_baseline = FALSE` removes trailing lines to either side of the histogram. (For histograms, the `rel_min_height` parameter doesn't work very well.) ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, height = stat(density))) + geom_density_ridges(stat = "binline", bins = 20, scale = 0.95, draw_baseline = FALSE) ``` ## Themes ridgeline plots tend to require some theme modifications to look good. Most importantly, the y-axis tick labels should be vertically aligned so that they are flush with the axis ticks rather than vertically centered. The ggridges package provides a theme `theme_ridges` that does this and a few other theme modifications. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + theme_ridges() ``` However, without any further modifications, there are still a few issues with this plot. First, the ridgeline for the virginica species is slightly cut off at the very top point. Second, the space between the x and y axis labels and the ridgelines is too large. We can fix both issues using the `expand` option for the axis scales. ```{r message=FALSE, warning=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = expand_scale(mult = c(0.01, .7))) + theme_ridges() ``` Instead of expanding the axis, you can also turn off clipping for the plot panel. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges() ``` By default, `theme_ridges` adds a grid, but the grid can be switched off when not needed. Also, axis titles can be centered. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE, center_axis_labels = TRUE) ``` If you prefer to use a different theme than `theme_ridges`, for example `theme_minimal`, it is still advisable to adjust the alignment of the axis tick labels and the axis scales. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_minimal(base_size = 14) + theme(axis.text.y = element_text(vjust = 0)) ``` ## Cyclical scales Many ridgeline plots improve in appearance if the filled areas are drawn with alternating colors. To simplify the generation of such plots, **ggridges** provides cyclical scales. These are scales that cycle through the aesthetic values provided. For example, if we use `scale_fill_cyclical(values = c("blue", "green"))` then `ggplot` will cycle through these two fill colors throughout the plot. ```{r message=FALSE} ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("blue", "green")) ``` By default, the cyclical scales will not draw a legend, because the legend will usually be confusing unless the labels are manually altered. Legends can be switched on via the `guide = "legend"` option, just like for all other scales. ```{r message=FALSE, fig.width = 5.5} ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("blue", "green"), guide = "legend") ``` Legends can be modified as usual. ```{r message=FALSE, fig.width = 5.5} ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical( name = "Fill colors", values = c("blue", "green"), labels = c("Fair" = "blue", "Good" = "green"), guide = "legend" ) ``` Cyclical scales are defined for all the common aesthetics one might want to change, such as color, size, alpha, and linetype, and the legends are combined when possible ```{r message=FALSE, fig.width = 6.5} ggplot(diamonds, aes(x = price, y = cut, fill = cut, color = cut)) + geom_density_ridges(scale = 4, size = 1) + scale_fill_cyclical( name = "Color scheme", values = c("blue", "green"), guide = "legend", labels = c("Fair" = "blue w/ black outline", "Good" = "green w/ yellow outline") ) + scale_color_cyclical( name = "Color scheme", values = c("black", "yellow"), guide = "legend", labels = c("Fair" = "blue w/ black outline", "Good" = "green w/ yellow outline") ) ``` Because these cyclical scales are generic **ggplot2** scales, they work with any geom that accepts the respective aesthetic. Thus, for example, we can make histograms with alternatingly colored bars. ```{r message=FALSE, fig.width = 6.5} ggplot(mpg, aes(x = class, fill = class, color = class)) + geom_bar(size = 1.5) + scale_fill_cyclical( name = "Color scheme", values = c("blue", "green"), guide = "legend", labels = c("blue w/ black outline", "green w/ yellow outline") ) + scale_color_cyclical( name = "Color scheme", values = c("black", "yellow"), guide = "legend", labels = c("blue w/ black outline", "green w/ yellow outline") ) ``` While the previous example won't win any design awards, more subtle effects can be helpful. ```{r message=FALSE, fig.width=5.5} mpg %>% group_by(class) %>% tally() %>% arrange(desc(n)) %>% mutate(class = factor(class, levels = class)) %>% ggplot(aes(x = class, y = n, fill = class)) + geom_col() + scale_fill_cyclical(values = c("#4040B0", "#9090F0")) + scale_y_continuous(expand = c(0, 0)) + theme_minimal() ``` ggridges/vignettes/gallery.Rmd0000644000176200001440000001436213606437134016175 0ustar liggesusers--- title: "Gallery of ggridges examples" author: "Claus O. Wilke" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: fig_width: 4.5 fig_height: 3 vignette: > %\VignetteIndexEntry{Gallery of ggridges examples} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- ```{r echo=FALSE, include=FALSE} library(ggplot2) library(ggridges) ``` ## Evolution of movie lengths over time Data from the IMDB, as provided in the ggplot2movies package. ```{r message=FALSE, warning=FALSE, fig.width = 6, fig.height = 6} library(ggplot2movies) ggplot(movies[movies$year>1912,], aes(x = length, y = year, group = year)) + geom_density_ridges(scale = 10, size = 0.25, rel_min_height = 0.03) + theme_ridges() + scale_x_continuous(limits = c(1, 200), expand = c(0, 0)) + scale_y_reverse( breaks = c(2000, 1980, 1960, 1940, 1920, 1900), expand = c(0, 0) ) + coord_cartesian(clip = "off") ``` ## Results from Catalan regional elections, 1980-2015 Modified after a figure originally created by [Marc Belzunces.](https://twitter.com/marcbeldata/) ```{r message=FALSE, warning=FALSE, fig.width = 6, fig.height = 8} library(dplyr) library(forcats) Catalan_elections %>% mutate(YearFct = fct_rev(as.factor(Year))) %>% ggplot(aes(y = YearFct)) + geom_density_ridges( aes(x = Percent, fill = paste(YearFct, Option)), alpha = .8, color = "white", from = 0, to = 100 ) + labs( x = "Vote (%)", y = "Election Year", title = "Indy vs Unionist vote in Catalan elections", subtitle = "Analysis unit: municipalities (n = 949)", caption = "Marc Belzunces (@marcbeldata) | Source: Idescat" ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + scale_fill_cyclical( breaks = c("1980 Indy", "1980 Unionist"), labels = c(`1980 Indy` = "Indy", `1980 Unionist` = "Unionist"), values = c("#ff0000", "#0000ff", "#ff8080", "#8080ff"), name = "Option", guide = "legend" ) + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE) ``` ## Temperatures in Lincoln, Nebraska Modified from a [blog post](http://austinwehrwein.com/data-visualization/it-brings-me-ggjoy/) by Austin Wehrwein. ```{r message=FALSE, warning=FALSE, fig.width = 7.5, fig.height = 5} ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = Month, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01, gradient_lwd = 1.) + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = expand_scale(mult = c(0.01, 0.25))) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + labs( title = 'Temperatures in Lincoln NE', subtitle = 'Mean temperatures (Fahrenheit) by month for 2016' ) + theme_ridges(font_size = 13, grid = TRUE) + theme(axis.title.y = element_blank()) ``` ## Visualization of Poisson random samples with different means Inspired by a [ggridges example](https://twitter.com/noamross/status/888405434381545472) by Noam Ross. ```{r message=FALSE, warning=FALSE, fig.width = 6, fig.height = 7} # generate data set.seed(1234) pois_data <- data.frame(mean = rep(1:5, each = 10)) pois_data$group <- factor(pois_data$mean, levels = 5:1) pois_data$value <- rpois(nrow(pois_data), pois_data$mean) # make plot ggplot(pois_data, aes(x = value, y = group, group = group)) + geom_density_ridges2(aes(fill = group), stat = "binline", binwidth = 1, scale = 0.95) + geom_text( stat = "bin", aes( y = group + 0.95*stat(count/max(count)), label = ifelse(stat(count) > 0, stat(count), "") ), vjust = 1.4, size = 3, color = "white", binwidth = 1 ) + scale_x_continuous( breaks = c(0:12), limits = c(-.5, 13), expand = c(0, 0), name = "random value" ) + scale_y_discrete( expand = expand_scale(add = c(0, 1.)), name = "Poisson mean", labels = c("5.0", "4.0", "3.0", "2.0", "1.0") ) + scale_fill_cyclical(values = c("#0000B0", "#7070D0")) + labs( title = "Poisson random samples with different means", subtitle = "sample size n=10" ) + guides(y = "none") + theme_ridges(grid = FALSE) + theme( axis.title.x = element_text(hjust = 0.5), axis.title.y = element_text(hjust = 0.5) ) ``` ## Height of Australian athletes ```{r message=FALSE, fig.width = 7, fig.height = 5.5} ggplot(Aus_athletes, aes(x = height, y = sport, color = sex, point_color = sex, fill = sex)) + geom_density_ridges( jittered_points = TRUE, scale = .95, rel_min_height = .01, point_shape = "|", point_size = 3, size = 0.25, position = position_points_jitter(height = 0) ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0), name = "height [cm]") + scale_fill_manual(values = c("#D55E0050", "#0072B250"), labels = c("female", "male")) + scale_color_manual(values = c("#D55E00", "#0072B2"), guide = "none") + scale_discrete_manual("point_color", values = c("#D55E00", "#0072B2"), guide = "none") + coord_cartesian(clip = "off") + guides(fill = guide_legend( override.aes = list( fill = c("#D55E00A0", "#0072B2A0"), color = NA, point_color = NA) ) ) + ggtitle("Height in Australian athletes") + theme_ridges(center = TRUE) ``` ## A cheese plot Inspired by [this tweet](https://twitter.com/lenkiefer/status/932237461337575429) by Leonard Kiefer. ```{r message=FALSE, fig.width = 6, fig.height = 5} set.seed(423) n1 <- 200 n2 <- 25 n3 <- 50 cols <- c('#F2DB2F', '#F7F19E', '#FBF186') cols_dark <- c("#D7C32F", "#DBD68C", "#DFD672") cheese <- data.frame( cheese = c(rep("buttercheese", n1), rep("Leerdammer", n2), rep("Swiss", n3)), x = c(runif(n1), runif(n2), runif(n3)), size = c( rnorm(n1, mean = .1, sd = .01), rnorm(n2, mean = 9, sd = 3), rnorm(n3, mean = 3, sd = 1) ) ) ggplot(cheese, aes(x = x, point_size = size, y = cheese, fill = cheese, color = cheese)) + geom_density_ridges( jittered_points = TRUE, point_color="white", scale = .8, rel_min_height = .2, size = 1.5 ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(limits = c(0, 1), expand = c(0, 0), name = "", breaks = NULL) + scale_point_size_continuous(range = c(0.01, 10), guide = "none") + scale_fill_manual(values = cols, guide = "none") + scale_color_manual(values = cols_dark, guide = "none") + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE, center = TRUE) ``` ggridges/R/0000755000176200001440000000000013606377467012271 5ustar liggesusersggridges/R/geoms.R0000644000176200001440000005061713606371763013530 0ustar liggesusers#' Plot a ridgeline (line with filled area underneath) #' #' Plots the sum of the `y` and `height` aesthetics versus `x`, filling the area between `y` and `y + height` with a color. #' Thus, the data mapped onto y and onto height must be in the same units. #' If you want relative scaling of the heights, you can use [`geom_density_ridges`] with `stat = "identity"`. #' #' In addition to drawing ridgelines, this geom can also draw points if they are provided as part of the dataset. #' The stat [`stat_density_ridges()`] takes advantage of this option to generate ridgeline plots with overlaid #' jittered points. #' #' @param mapping Set of aesthetic mappings created by [`aes()`] or #' [`aes_()`]. If specified and `inherit.aes = TRUE` (the #' default), it is combined with the default mapping at the top level of the #' plot. You must supply `mapping` if there is no plot mapping. #' @param data The data to be displayed in this layer. There are three #' options: #' #' If `NULL`, the default, the data is inherited from the plot #' data as specified in the call to [`ggplot()`]. #' #' A `data.frame`, or other object, will override the plot #' data. #' #' A `function` will be called with a single argument, #' the plot data. The return value must be a `data.frame.`, and #' will be used as the layer data. #' @param stat The statistical transformation to use on the data for this #' layer, as a string. #' @param position Position adjustment, either as a string, or the result of #' a call to a position adjustment function. #' @param show.legend logical. Should this layer be included in the legends? #' `NA`, the default, includes if any aesthetics are mapped. #' `FALSE` never includes, and `TRUE` always includes. #' @param inherit.aes If `FALSE`, overrides the default aesthetics, #' rather than combining with them. #' @param na.rm If `FALSE`, the default, missing values are removed with #' a warning. If `TRUE`, missing values are silently removed. #' @param ... other arguments passed on to [`layer()`]. These are #' often aesthetics, used to set an aesthetic to a fixed value, like #' `color = "red"` or `size = 3`. They may also be parameters #' to the paired geom/stat. #' #' @section Aesthetics: #' #' Required aesthetics are in bold. #' #' * **`x`** #' * **`y`** #' * **`height`** Height of the ridgeline, measured from the respective `y` value. Assumed to be positive, though this is not required. #' * `group` Defines the grouping. Required when the dataset contains multiple distinct ridgelines. Will typically be the same #' variable as is mapped to `y`. #' * `scale` A scaling factor to scale the height of the ridgelines. #' A value of 1 indicates that the heights are taken as is. This aesthetic can be used to convert #' `height` units into `y` units. #' * `min_height` A height cutoff on the drawn ridgelines. All values that fall below this cutoff will be removed. #' The main purpose of this cutoff is to remove long tails right at the baseline level, but other uses are possible. #' The cutoff is applied before any height #' scaling is applied via the `scale` aesthetic. Default is 0, so negative values are removed. #' * `colour` Color of the ridgeline #' * `fill` Fill color of the area under the ridgeline #' * `alpha` Transparency level of `fill`. Not applied to `color`. If you want transparent lines, you can set their #' color as RGBA value, e.g. #FF0000A0 for partially transparent red. #' * `group` Grouping, to draw multiple ridgelines from one dataset #' * `linetype` Linetype of the ridgeline #' * `size` Line thickness #' * `point_shape`, `point_colour`, `point_size`, `point_fill`, `point_alpha`, `point_stroke` Aesthetics applied #' to points drawn in addition to ridgelines. #' #' @examples #' library(ggplot2) #' #' d <- data.frame(x = rep(1:5, 3), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), #' height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) #' ggplot(d, aes(x, y, height = height, group = y)) + geom_ridgeline(fill="lightblue") #' #' @importFrom ggplot2 layer #' @export geom_ridgeline <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) { layer( data = data, mapping = mapping, stat = stat, geom = GeomRidgeline, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, ... ) ) } #' @rdname geom_ridgeline #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto Geom #' @importFrom plyr summarise #' @export GeomRidgeline <- ggproto("GeomRidgeline", Geom, default_aes = aes( # ridgeline aesthetics color = "black", fill = "grey70", y = 0, size = 0.5, linetype = 1, min_height = 0, scale = 1, alpha = NA, datatype = "ridgeline", # point aesthetics with default point_shape = 19, point_size = 1.5, point_stroke = 0.5, # point aesthetics, inherited point_colour = NULL,# point_color = NULL, point_fill = NULL, point_alpha = NULL, # vline aesthetics, all inherited vline_colour = NULL, #vline_color = NULL, vline_size = NULL, vline_linetype = NULL ), required_aes = c("x", "y", "height"), optional_aes = c("point_color", "vline_color"), extra_params = c("na.rm", "jittered_points"), setup_data = function(self, data, params) { if (!"scale" %in% names(data)) { if (!"scale" %in% names(params)) data <- cbind(data, scale = self$default_aes$scale) else data <- cbind(data, scale = params$scale) } if (!"min_height" %in% names(data)){ if (!"min_height" %in% names(params)) data <- cbind(data, min_height = self$default_aes$min_height) else data <- cbind(data, min_height = params$min_height) } transform(data, ymin = y, ymax = y + scale*height) }, draw_key = function(data, params, size) { lwd <- min(data$size, min(size) / 4) rect_grob <- grid::rectGrob( width = grid::unit(1, "npc") - grid::unit(lwd, "mm"), height = grid::unit(1, "npc") - grid::unit(lwd, "mm"), gp = grid::gpar( col = data$colour, fill = alpha(data$fill, data$alpha), lty = data$linetype, lwd = lwd * .pt, linejoin = "mitre" ) ) # if vertical lines were drawn then we need to add them to the legend also if (is.null(params$quantile_lines) || !params$quantile_lines) { vlines_grob <- grid::nullGrob() } else { vlines_grob <- grid::segmentsGrob(0.5, 0.1, 0.5, 0.9, gp = grid::gpar( col = data$vline_colour %||% data$vline_color %||% data$colour, lwd = (data$vline_size %||% data$size) * .pt, lty = data$vline_linetype %||% data$linetype, lineend = "butt" ) ) } # if jittered points were drawn then we need to add them to the legend also if (is.null(params$jittered_points) || !params$jittered_points) { point_grob <- grid::nullGrob() } else { point_grob <- grid::pointsGrob(0.5, 0.5, pch = data$point_shape, gp = grid::gpar( col = alpha( data$point_colour %||% data$point_color %||% data$colour, data$point_alpha %||% data$alpha ), fill = alpha( data$point_fill %||% data$fill, data$point_alpha %||% data$alpha ), fontsize = data$point_size * .pt + data$point_stroke * .stroke / 2, lwd = data$point_stroke * .stroke / 2 ) ) } grid::grobTree(rect_grob, vlines_grob, point_grob) }, handle_na = function(data, params) { data }, draw_panel = function(self, data, panel_params, coord, ...) { groups <- split(data, factor(data$group)) # sort list so highest ymin values are in the front # we take a shortcut here and look only at the first ymin value given o <- order(unlist(lapply(groups, function(data){data$ymin[1]})), decreasing = TRUE) groups <- groups[o] grobs <- lapply(groups, function(group) { self$draw_group(group, panel_params, coord, ...) }) ggname(snake_class(self), gTree( children = do.call("gList", grobs) )) }, draw_group = function(self, data, panel_params, coord, na.rm = FALSE) { if (na.rm) data <- data[stats::complete.cases(data[c("x", "ymin", "ymax")]), ] # split data into data types (ridgeline, vline, point) data_list <- split(data, factor(data$datatype)) point_grob <- self$make_point_grob(data_list[["point"]], panel_params, coord) vline_grob <- self$make_vline_grob(data_list[["vline"]], panel_params, coord) data <- data_list[["ridgeline"]] # if the final data set is empty then we're done here if (is.null(data)) { return(grid::grobTree(vline_grob, point_grob)) } # otherwise, continue. First we order the data, in preparation for polygon drawing data <- data[order(data$group, data$x), ] # remove all points that fall below the minimum height data$ymax[data$height < data$min_height] <- NA # Check that aesthetics are constant aes <- unique(data[c("colour", "fill", "size", "linetype", "alpha")]) if (nrow(aes) > 1) { stop("Aesthetics can not vary along a ridgeline") } aes <- as.list(aes) # Instead of removing NA values from the data and plotting a single # polygon, we want to "stop" plotting the polygon whenever we're # missing values and "start" a new polygon as soon as we have new # values. We do this by creating an id vector for polygonGrob that # has distinct polygon numbers for sequences of non-NA values and NA # for NA values in the original data. Example: c(NA, 2, 2, 2, NA, NA, # 4, 4, 4, NA) missing_pos <- !stats::complete.cases(data[c("x", "ymin", "ymax")]) ids <- cumsum(missing_pos) + 1 ids[missing_pos] <- NA # munching for polygon positions <- plyr::summarise(data, x = c(x, rev(x)), y = c(ymax, rev(ymin)), id = c(ids, rev(ids))) munched_poly <- ggplot2::coord_munch(coord, positions, panel_params) # munching for line positions <- plyr::summarise(data, x = x, y = ymax, id = ids) munched_line <- ggplot2::coord_munch(coord, positions, panel_params) # calculate line and area grobs line_grob <- self$make_line_grob(munched_line, munched_poly, aes) area_grob <- self$make_area_grob(munched_poly, aes) # combine everything and return grid::grobTree(area_grob, vline_grob, line_grob, point_grob) }, make_point_grob = function(data, panel_params, coord) { if (is.null(data)) { return(grid::nullGrob()) } data$y <- data$ymin coords <- coord$transform(data, panel_params) ggname("geom_ridgeline", grid::pointsGrob( coords$x, coords$y, pch = coords$point_shape, gp = grid::gpar( col = alpha( data$point_colour %||% data$point_color %||% data$colour, data$point_alpha %||% data$alpha ), fill = alpha( data$point_fill %||% data$fill, data$point_alpha %||% data$alpha ), # Stroke is added around the outside of the point fontsize = coords$point_size * .pt + coords$point_stroke * .stroke / 2, lwd = coords$point_stroke * .stroke / 2 ) ) ) }, make_vline_grob = function(data, panel_params, coord) { if (is.null(data)) { return(grid::nullGrob()) } data$xend <- data$x data$y <- data$ymin data$yend <- data$ymax data$alpha <- NA # copy vline aesthetics over if set data$colour <- data$vline_colour %||% data$vline_color %||% data$colour data$linetype <- data$vline_linetype %||% data$linetype data$size <- data$vline_size %||% data$size ggplot2::GeomSegment$draw_panel(data, panel_params, coord) }, make_line_grob = function(munched_line, munched_poly, aes) { ggname("geom_ridgeline", grid::polylineGrob( munched_line$x, munched_line$y, id = munched_line$id, default.units = "native", gp = grid::gpar( col = aes$colour, lwd = aes$size * .pt, lty = aes$linetype) ) ) }, make_area_grob = function(munched_poly, aes) { ggname("geom_ridgeline", grid::polygonGrob( munched_poly$x, munched_poly$y, id = munched_poly$id, default.units = "native", gp = grid::gpar( fill = ggplot2::alpha(aes$fill, aes$alpha), lty = 0) ) ) } ) #' Create ridgeline plot #' #' `geom_density_ridges` arranges multiple density plots in a staggered fashion, as in the cover of the famous Joy Division album Unknown Pleasures. #' #' By default, this geom calculates densities from the point data mapped onto the x axis. If density calculation is #' not wanted, use `stat="identity"` or use [`geom_ridgeline`]. The difference between `geom_density_ridges` and [`geom_ridgeline`] #' is that `geom_density_ridges` will provide automatic scaling of the ridgelines (controlled by the `scale` aesthetic), whereas #' [geom_ridgeline] will plot the data as is. Note that when you set `stat="identity"`, the `height` aesthetic must #' be provided. #' #' Note that the default [`stat_density_ridges`] makes joint density estimation across all datasets. This may not generate #' the desired result when using faceted plots. As an alternative, you can set `stat = "density"` to use [`stat_density`]. #' In this case, it is required to add the aesthetic mapping `height = ..density..` (see examples). #' #' @param panel_scaling If `TRUE`, the default, relative scaling is calculated separately #' for each panel. If `FALSE`, relative scaling is calculated globally. #' @inheritParams geom_ridgeline #' #' @section Aesthetics: #' #' Required aesthetics are in bold. #' #' * **`x`** #' * **`y`** #' * `group` Defines the grouping. Not needed if a categorical variable is mapped onto `y`, but needed otherwise. Will typically be the same #' variable as is mapped to `y`. #' * `height` The height of each ridgeline at the respective x value. Automatically calculated and #' provided by [`stat_density_ridges`] if the default stat is not changed. #' * `scale` A scaling factor to scale the height of the ridgelines relative to the spacing between them. #' A value of 1 indicates that the maximum point of any ridgeline touches the baseline right above, assuming #' even spacing between baselines. #' * `rel_min_height` Lines with heights below this cutoff will be removed. The cutoff is measured relative to the #' overall maximum, so `rel_min_height=0.01` would remove everything that is 1\% or less than the highest point among all #' ridgelines. Default is 0, so nothing is removed. #' alpha #' * `colour`, `fill`, `group`, `alpha`, `linetype`, `size`, as in [`geom_ridgeline`]. #' * `point_shape`, `point_colour`, `point_size`, `point_fill`, `point_alpha`, `point_stroke`, as in [`geom_ridgeline`]. #' #' @importFrom ggplot2 layer #' @export #' @examples #' library(ggplot2) #' #' # set the `rel_min_height` argument to remove tails #' ggplot(iris, aes(x = Sepal.Length, y = Species)) + #' geom_density_ridges(rel_min_height = 0.005) + #' scale_y_discrete(expand = c(0.01, 0)) + #' scale_x_continuous(expand = c(0.01, 0)) + #' theme_ridges() #' #' # set the `scale` to determine how much overlap there is among the plots #' ggplot(diamonds, aes(x = price, y = cut)) + #' geom_density_ridges(scale = 4) + #' scale_y_discrete(expand = c(0.01, 0)) + #' scale_x_continuous(expand = c(0.01, 0)) + #' theme_ridges() #' #' # the same figure with colors, and using the ggplot2 density stat #' ggplot(diamonds, aes(x = price, y = cut, fill = cut, height = ..density..)) + #' geom_density_ridges(scale = 4, stat = "density") + #' scale_y_discrete(expand = c(0.01, 0)) + #' scale_x_continuous(expand = c(0.01, 0)) + #' scale_fill_brewer(palette = 4) + #' theme_ridges() + theme(legend.position = "none") geom_density_ridges <- function(mapping = NULL, data = NULL, stat = "density_ridges", position = "points_sina", panel_scaling = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) { layer( data = data, mapping = mapping, stat = stat, geom = GeomDensityRidges, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, panel_scaling = panel_scaling, ... ) ) } #' @rdname geom_density_ridges #' @format NULL #' @usage NULL #' @importFrom grid gTree gList #' @export GeomDensityRidges <- ggproto("GeomDensityRidges", GeomRidgeline, default_aes = aes( # ridgeline aesthetics color = "black", fill = "grey70", size = 0.5, linetype = 1, rel_min_height = 0, scale = 1.8, alpha = NA, datatype = "ridgeline", # point aesthetics with default point_shape = 19, point_size = 1.5, point_stroke = 0.5, # point aesthetics, inherited point_colour = NULL, #point_color = NULL, point_fill = NULL, point_alpha = NULL, # vline aesthetics, all inherited vline_colour = NULL, #vline_color = NULL, vline_size = NULL, vline_linetype = NULL ), required_aes = c("x", "y", "height"), optional_aes = c("point_color", "vline_color"), extra_params = c("na.rm", "panel_scaling"), setup_data = function(self, data, params) { # provide default for panel scaling parameter if it doesn't exist, # happens if the geom is called from a stat if (is.null(params$panel_scaling)) { params$panel_scaling <- TRUE } # calculate internal scale yrange = max(data$y) - min(data$y) n = length(unique(data$y)) if (n<2) { hmax <- max(data$height, na.rm = TRUE) iscale <- 1 } else { # scale per panel or globally? if (params$panel_scaling) { heights <- split(data$height, data$PANEL) max_heights <- vapply(heights, max, numeric(1), na.rm = TRUE) hmax <- max_heights[data$PANEL] iscale <- yrange/((n-1)*hmax) } else { hmax <- max(data$height, na.rm = TRUE) iscale <- yrange/((n-1)*hmax) } } #print(iscale) #print(hmax) data <- cbind(data, iscale) if (!"scale" %in% names(data)) { if (!"scale" %in% names(params)) data <- cbind(data, scale = self$default_aes$scale) else data <- cbind(data, scale = params$scale) } if (!"rel_min_height" %in% names(data)){ if (!"rel_min_height" %in% names(params)) data <- cbind(data, rel_min_height = self$default_aes$rel_min_height) else data <- cbind(data, rel_min_height = params$rel_min_height) } transform(data, ymin = y, ymax = y + iscale*scale*height, min_height = hmax*rel_min_height) } ) #' `geom_density_ridges2` is identical to `geom_density_ridges` except it draws closed polygons rather than ridgelines. #' #' @rdname geom_density_ridges #' @importFrom ggplot2 layer #' @export #' @examples #' #' # use geom_density_ridges2() instead of geom_density_ridges() for solid polygons #' ggplot(iris, aes(x = Sepal.Length, y = Species)) + #' geom_density_ridges2() + #' scale_y_discrete(expand = c(0.01, 0)) + #' scale_x_continuous(expand = c(0.01, 0)) + #' theme_ridges() geom_density_ridges2 <- function(mapping = NULL, data = NULL, stat = "density_ridges", position = "points_sina", panel_scaling = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) { layer( data = data, mapping = mapping, stat = stat, geom = GeomDensityRidges2, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, panel_scaling = panel_scaling, ... ) ) } #' @rdname geom_density_ridges #' @format NULL #' @usage NULL #' @export GeomDensityRidges2 <- ggproto("GeomDensityRidges2", GeomDensityRidges, make_line_grob = function(munched_line, munched_poly, aes) { grid::nullGrob() }, make_area_grob = function(munched_poly, aes) { ggname("geom_density_ridges2", grid::polygonGrob( munched_poly$x, munched_poly$y, id = munched_poly$id, default.units = "native", gp = grid::gpar( fill = ggplot2::alpha(aes$fill, aes$alpha), col = aes$colour, lwd = aes$size * .pt, lty = aes$linetype) )) } ) ggridges/R/utils.R0000644000176200001440000000200213606371763013537 0ustar liggesusers #' Reduce a list to a single value by iteratively applying a binary function #' #' Inspired by \code{reduce()} from the \code{purrr} package #' #' @param .x A list or atomic vector. #' @param .f A 2-argument function. The function will be #' passed the accumulated value as the first argument and the "next" value #' as the second argument. #' @param ... Additional arguments passed on to `.f`. #' @param .init If supplied, will be used as the first value to start #' the accumulation, rather than using \code{x[[1]]}. This is useful if #' you want to ensure that `reduce` returns a correct value when `.x` #' is empty. If missing, and `x` is empty, will throw an error. #' #' @author Jonathon Love #' reduce <- function(.x, .f, ..., .init) { if (missing(.init)) { if (length(.x) == 0) stop('`.x` is empty, and no `.init` supplied') v <- .x[[1]] i <- 2 } else { v <- .init i <- 1 } while (i <= length(.x)) { v <- .f(v, .x[[i]], ...) i <- i + 1 } v } ggridges/R/utils_ggplot2.R0000644000176200001440000000313613606371763015206 0ustar liggesusers# code that needed to be copied from ggplot2 # Name ggplot grid object, from ggplot2/R/utilities-grid.r # Convenience function to name grid objects # # @keyword internal ggname <- function(prefix, grob) { grob$name <- grid::grobName(grob, prefix) grob } # From ggplot2/R/utilities.r snakeize <- function(x) { x <- gsub("([A-Za-z])([A-Z])([a-z])", "\\1_\\2\\3", x) x <- gsub(".", "_", x, fixed = TRUE) x <- gsub("([a-z])([A-Z])", "\\1_\\2", x) tolower(x) } snake_class <- function(x) { snakeize(class(x)[1]) } with_seed_null <- function(seed, code) { if (is.null(seed)) { code } else { withr::with_seed(seed, code) } } "%||%" <- function(a, b) { if (!is.null(a)) a else b } # ggplot2 range code, from ggplot2/R/range.r #' @importFrom ggplot2 ggproto #' @noRd Range <- ggproto("Range", NULL, range = NULL, reset = function(self) { self$range <- NULL } ) #' @importFrom scales train_discrete #' @noRd RangeDiscrete <- ggproto("RangeDiscrete", Range, train = function(self, x, drop = FALSE, na.rm = FALSE) { self$range <- scales::train_discrete(x, self$range, drop = drop, na.rm = na.rm) } ) discrete_range <- function() { ggproto(NULL, RangeDiscrete) } # ggplot2 aes code, from ggplot2/R/aes.r # Look up the scale that should be used for a given aesthetic aes_to_scale <- function(var) { var[var %in% c("x", "xmin", "xmax", "xend", "xintercept")] <- "x" var[var %in% c("y", "ymin", "ymax", "yend", "yintercept")] <- "y" var } # Figure out if an aesthetic is a position aesthetic or not is_position_aes <- function(vars) { aes_to_scale(vars) %in% c("x", "y") } ggridges/R/scale-vline.R0000644000176200001440000001033113606371763014605 0ustar liggesusers#' Scales for vline aesthetics #' #' These are various scales that can be applied to vline aesthetics, such as #' `vline_color`, `vline_size`, `vline_linetype`. The individual scales all have the #' same usage as existing standard ggplot2 scales, only the name differs. #' #' @name scale_vline #' @seealso See [`scale_point_color_hue()`] for specific scales for point aesthetics #' and [`scale_discrete_manual()`] for a general discrete scale. #' @examples #' library(ggplot2) #' #' # default scales #' ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species, color = Species)) + #' geom_density_ridges( #' aes(vline_color = Species, vline_linetype = Species), #' alpha = .4, quantile_lines = TRUE #' ) + #' theme_ridges() #' #' # modified scales #' ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species, color = Species)) + #' geom_density_ridges( #' aes(vline_color = Species), #' alpha = .4, quantile_lines = TRUE #' ) + #' scale_fill_hue(l = 50) + #' scale_vline_color_hue(l = 30) + #' theme_ridges() #' @aliases NULL NULL #' `scale_vline_linetype()`: Equivalent to [`scale_linetype()`]. #' @rdname scale_vline #' @usage NULL #' @export scale_vline_linetype <- function(..., na.value = "blank", aesthetics = "vline_linetype") { discrete_scale(aesthetics, "linetype_d", scales::linetype_pal(), na.value = na.value, ...) } #' `scale_vline_size_continuous()`: Equivalent to [`scale_size_continuous()`]. #' @rdname scale_vline #' @usage NULL #' @export scale_vline_size_continuous <- function(name = ggplot2::waiver(), breaks = ggplot2::waiver(), labels = ggplot2::waiver(), limits = NULL, range = c(1, 6), trans = "identity", guide = "legend", aesthetics = "vline_size") { ggplot2::continuous_scale(aesthetics, "area", scales::area_pal(range), name = name, breaks = breaks, labels = labels, limits = limits, trans = trans, guide = guide) } #' `scale_vline_colour_hue()`: Equivalent to [`scale_colour_hue()`]. #' @rdname scale_vline #' @usage NULL #' @export scale_vline_colour_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1, na.value = "grey50", aesthetics = "vline_colour") { ggplot2::discrete_scale(aesthetics, "hue", scales::hue_pal(h, c, l, h.start, direction), na.value = na.value, ...) } #' @rdname scale_vline #' @usage NULL #' @export scale_vline_color_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1, na.value = "grey50", aesthetics = "vline_color") { ggplot2::discrete_scale(aesthetics, "hue", scales::hue_pal(h, c, l, h.start, direction), na.value = na.value, ...) } #' `scale_vline_colour_gradient()`: Equivalent to [`scale_colour_gradient()`]. #' @rdname scale_vline #' @usage NULL #' @export scale_vline_colour_gradient <- function(..., low = "#132B43", high = "#56B1F7", space = "Lab", na.value = "grey50", guide = "none", aesthetics = "vline_colour") { ggplot2::continuous_scale(aesthetics, "gradient", scales::seq_gradient_pal(low, high, space), na.value = na.value, guide = guide, ...) } #' @rdname scale_vline #' @usage NULL #' @export scale_vline_color_gradient <- function(..., low = "#132B43", high = "#56B1F7", space = "Lab", na.value = "grey50", guide = "none", aesthetics = "vline_color") { ggplot2::continuous_scale(aesthetics, "gradient", scales::seq_gradient_pal(low, high, space), na.value = na.value, guide = guide, ...) } # default scales #' @rdname scale_vline #' @usage NULL #' @export scale_vline_linetype_discrete <- scale_vline_linetype #' @rdname scale_vline #' @usage NULL #' @export scale_vline_color_discrete <- scale_vline_color_hue #' @rdname scale_vline #' @usage NULL #' @export scale_vline_colour_discrete <- scale_vline_colour_hue #' @rdname scale_vline #' @usage NULL #' @export scale_vline_color_continuous <- scale_vline_color_gradient #' @rdname scale_vline #' @usage NULL #' @export scale_vline_colour_continuous <- scale_vline_colour_gradient ggridges/R/stats.R0000644000176200001440000003756313606411702013545 0ustar liggesusers# Code for stat_density_ridges based on stat_density_common in the "extending ggplot2" vignette #' Stat for density ridgeline plots #' #' This stat is the default stat used by [`geom_density_ridges`]. It is very similar to [`stat_density`], #' however there are a few differences. Most importantly, the density bandwidth is chosen across #' the entire dataset. #' #' @param geom The geometric object to use to display the data. #' @param bandwidth Bandwidth used for density calculation. If not provided, is estimated from the data. #' @param from,to The left and right-most points of the grid at which the density is to be estimated, #' as in [`density()`]. If not provided, these are estimated from the data range and the bandwidth. #' @param jittered_points If `TRUE`, carries the original point data over to the processed data frame, #' so that individual points can be drawn by the various ridgeline geoms. The specific position of these #' points is controlled by various position objects, e.g. [`position_points_sina()`] or [`position_raincloud()`]. #' @param quantile_lines If `TRUE`, enables the drawing of quantile lines. Overrides the `calc_ecdf` setting #' and sets it to `TRUE`. #' @param calc_ecdf If `TRUE`, `stat_density_ridges` calculates an empirical cumulative distribution function (ecdf) #' and returns a variable `ecdf` and a variable `quantile`. Both can be mapped onto aesthetics via #' `stat(ecdf)` and `stat(quantile)`, respectively. #' @param quantiles Sets the number of quantiles the data should be broken into. Used if either `calc_ecdf = TRUE` #' or `quantile_lines = TRUE`. If `quantiles` is an integer then the data will be cut into that many equal quantiles. #' If it is a vector of probabilities then the data will cut by them. #' @param quantile_fun Function that calculates quantiles. The function needs to accept two parameters, #' a vector `x` holding the raw data values and a vector `probs` providing the probabilities that #' define the quantiles. Default is `quantile`. #' @param n The number of equally spaced points at which the density is to be estimated. Should be a power of 2. Default #' is 512. #' @inheritParams geom_ridgeline #' @importFrom ggplot2 layer #' @examples #' library(ggplot2) #' #' # Examples of coloring by ecdf or quantiles #' ggplot(iris, aes(x = Sepal.Length, y = Species, fill = factor(stat(quantile)))) + #' stat_density_ridges( #' geom = "density_ridges_gradient", #' calc_ecdf = TRUE, #' quantiles = 5 #' ) + #' scale_fill_viridis_d(name = "Quintiles") + #' theme_ridges() #' #' ggplot(iris, #' aes( #' x = Sepal.Length, y = Species, fill = 0.5 - abs(0.5-stat(ecdf)) #' )) + #' stat_density_ridges(geom = "density_ridges_gradient", calc_ecdf = TRUE) + #' scale_fill_viridis_c(name = "Tail probability", direction = -1) + #' theme_ridges() #' #' ggplot(iris, #' aes( #' x = Sepal.Length, y = Species, fill = factor(stat(quantile)) #' )) + #' stat_density_ridges( #' geom = "density_ridges_gradient", #' calc_ecdf = TRUE, quantiles = c(0.025, 0.975) #' ) + #' scale_fill_manual( #' name = "Probability", #' values = c("#FF0000A0", "#A0A0A0A0", "#0000FFA0"), #' labels = c("(0, 0.025]", "(0.025, 0.975]", "(0.975, 1]") #' ) + #' theme_ridges() #' @export stat_density_ridges <- function(mapping = NULL, data = NULL, geom = "density_ridges", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, bandwidth = NULL, from = NULL, to = NULL, jittered_points = FALSE, quantile_lines = FALSE, calc_ecdf = FALSE, quantiles = 4, quantile_fun = quantile, n = 512, ...) { layer( stat = StatDensityRidges, data = data, mapping = mapping, geom = geom, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list(bandwidth = bandwidth, from = from, to = to, calc_ecdf = calc_ecdf, quantiles = quantiles, jittered_points = jittered_points, quantile_lines = quantile_lines, quantile_fun = quantile_fun, n = n, na.rm = na.rm, ...) ) } #' @rdname stat_density_ridges #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto Stat #' @export StatDensityRidges <- ggproto("StatDensityRidges", Stat, required_aes = "x", default_aes = aes(height = ..density..), calc_panel_params = function(data, params) { if (is.null(params$bandwidth)) { xdata <- na.omit(data.frame(x=data$x, group=data$group)) xs <- split(xdata$x, xdata$group) xs_mask <- vapply(xs, length, numeric(1)) > 1 bws <- vapply(xs[xs_mask], bw.nrd0, numeric(1)) bw <- mean(bws, na.rm = TRUE) message("Picking joint bandwidth of ", signif(bw, 3)) params$bandwidth <- bw } if (is.null(params$from)) { params$from <- min(data$x, na.rm=TRUE) - 3 * params$bandwidth } if (is.null(params$to)) { params$to <- max(data$x, na.rm=TRUE) + 3 * params$bandwidth } data.frame( bandwidth = params$bandwidth, from = params$from, to = params$to ) }, setup_params = function(self, data, params) { # calculate bandwidth, min, and max for each panel separately panels <- split(data, data$PANEL) pardata <- lapply(panels, self$calc_panel_params, params) pardata <- reduce(pardata, rbind) if (length(params$quantiles) > 1 && (max(params$quantiles, na.rm = TRUE) > 1 || min(params$quantiles, na.rm = TRUE) < 0)) { stop('invalid quantiles used: c(', paste0(params$quantiles, collapse = ','), ') must be within [0, 1] range') } params$bandwidth <- pardata$bandwidth params$from <- pardata$from params$to <- pardata$to params }, compute_group = function(data, scales, from, to, bandwidth = 1, calc_ecdf = FALSE, jittered_points = FALSE, quantile_lines = FALSE, quantiles = 4, quantile_fun = quantile, n = 512) { # ignore too small groups if(nrow(data) < 3) return(data.frame()) if (is.null(calc_ecdf)) calc_ecdf <- FALSE if (is.null(jittered_points)) jittered_points <- FALSE if (is.null(quantile_lines)) quantile_lines <- FALSE # when quantile lines are requested, we also calculate ecdf # this simplifies things for now; in principle, could disentangle # the two if (quantile_lines) calc_ecdf <- TRUE panel <- unique(data$PANEL) if (length(panel) > 1) { stop("Error: more than one panel in compute group; something's wrong.") } panel_id <- as.numeric(panel) d <- stats::density( data$x, bw = bandwidth[panel_id], from = from[panel_id], to = to[panel_id], na.rm = TRUE, n = n ) # calculate maximum density for scaling maxdens <- max(d$y, na.rm = TRUE) # make interpolating function for density line densf <- approxfun(d$x, d$y, rule = 2) # calculate jittered original points if requested if (jittered_points) { df_jittered <- data.frame( x = data$x, # actual jittering is handled in the position argument density = densf(data$x), ndensity = densf(data$x) / maxdens, datatype = "point", stringsAsFactors = FALSE) # see if we need to carry over other point data # capture all data columns starting with "point", as those are relevant for point aesthetics df_points <- data[grepl("point_", names(data))] # uncomment following line to switch off carrying over data #df_points <- data.frame() if (ncol(df_points) == 0) { df_points <- NULL df_points_dummy <- NULL } else { # combine additional points data into results dataframe df_jittered <- cbind(df_jittered, df_points) # make a row of dummy data to merge with the other dataframes df_points_dummy <- na.omit(df_points)[1, , drop = FALSE] } } else { df_jittered <- NULL df_points_dummy <- NULL } # calculate quantiles, needed for both quantile lines and ecdf if ((length(quantiles)==1) && (all(quantiles >= 1))) { if (quantiles > 1) { probs <- seq(0, 1, length.out = quantiles + 1)[2:quantiles] } else { probs <- NA } } else { probs <- quantiles probs[probs < 0 | probs > 1] <- NA } qx <- na.omit(quantile_fun(data$x, probs = probs)) # if requested, add data frame for quantile lines df_quantiles <- NULL if (quantile_lines && length(qx) > 0) { qy <- densf(qx) df_quantiles <- data.frame( x = qx, density = qy, ndensity = qy / maxdens, datatype = "vline", stringsAsFactors = FALSE ) if (!is.null(df_points_dummy)){ # add in dummy points data if necessary df_quantiles <- data.frame(df_quantiles, as.list(df_points_dummy)) } } # combine the quantiles and jittered points data frames into one, the non-density frame df_nondens <- rbind(df_quantiles, df_jittered) if (calc_ecdf) { n <- length(d$x) ecdf <- c(0, cumsum(d$y[1:(n-1)]*(d$x[2:n]-d$x[1:(n-1)]))) ecdf_fun <- approxfun(d$x, ecdf, rule = 2) ntile <- findInterval(d$x, qx, left.open = TRUE) + 1 # if make changes here, make them also below if (!is.null(df_nondens)) { # we add data for ecdf and quantiles back to all other data points df_nondens <- data.frame( df_nondens, ecdf = ecdf_fun(df_nondens$x), quantile = findInterval(df_nondens$x, qx, left.open = TRUE) + 1 ) } df_density <- data.frame( x = d$x, density = d$y, ndensity = d$y / maxdens, ecdf = ecdf, quantile = ntile, datatype = "ridgeline", stringsAsFactors = FALSE ) } else { df_density <- data.frame( x = d$x, density = d$y, ndensity = d$y / maxdens, datatype = "ridgeline", stringsAsFactors = FALSE ) } if (!is.null(df_points_dummy)){ # add in dummy points data if necessary df_density <- data.frame(df_density, as.list(df_points_dummy)) } # now combine everything and turn quantiles into factor df_final <- rbind(df_density, df_nondens) if ("quantile" %in% names(df_final)) { df_final$quantile <- factor(df_final$quantile) } df_final } ) #' Stat for histogram ridgeline plots #' #' Works like `stat_bin` except that the output is a ridgeline describing the histogram rather than #' a set of counts. #' #' @param draw_baseline If `FALSE`, removes lines along 0 counts. Defaults to `TRUE`. #' @param pad If `TRUE`, adds empty bins at either end of x. This ensures that the binline always goes #' back down to 0. Defaults to `TRUE`. #' @inheritParams ggplot2::stat_bin #' #' @examples #' library(ggplot2) #' #' ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species, fill = Species)) + #' geom_density_ridges(stat = "binline", bins = 20, scale = 2.2) + #' scale_y_discrete(expand = c(0, 0)) + #' scale_x_continuous(expand = c(0, 0)) + #' coord_cartesian(clip = "off") + #' theme_ridges() #' #' ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species, fill = Species)) + #' stat_binline(bins = 20, scale = 2.2, draw_baseline = FALSE) + #' scale_y_discrete(expand = c(0, 0)) + #' scale_x_continuous(expand = c(0, 0)) + #' scale_fill_grey() + #' coord_cartesian(clip = "off") + #' theme_ridges() + #' theme(legend.position = 'none') #' #' library(ggplot2movies) #' ggplot(movies[movies$year>1989,], aes(x = length, y = year, fill = factor(year))) + #' stat_binline(scale = 1.9, bins = 40) + #' scale_x_continuous(limits = c(1, 180), expand = c(0, 0)) + #' scale_y_reverse(expand = c(0, 0)) + #' scale_fill_viridis_d(begin = 0.3, option = "B") + #' coord_cartesian(clip = "off") + #' labs(title = "Movie lengths 1990 - 2005") #' theme_ridges() + #' theme(legend.position = "none") #' #' count_data <- data.frame( #' group = rep(letters[1:5], each = 10), #' mean = rep(1:5, each = 10) #' ) #' count_data$group <- factor(count_data$group, levels = letters[5:1]) #' count_data$count <- rpois(nrow(count_data), count_data$mean) #' #' ggplot(count_data, aes(x = count, y = group, group = group)) + #' geom_density_ridges2( #' stat = "binline", #' aes(fill = group), #' binwidth = 1, #' scale = 0.95 #' ) + #' geom_text( #' stat = "bin", #' aes(y = group + 0.9*stat(count/max(count)), #' label = ifelse(stat(count) > 0, stat(count), "")), #' vjust = 1.2, size = 3, color = "white", binwidth = 1 #' ) + #' scale_x_continuous(breaks = c(0:12), limits = c(-.5, 13), expand = c(0, 0)) + #' scale_y_discrete(expand = c(0, 0)) + #' scale_fill_cyclical(values = c("#0000B0", "#7070D0")) + #' guides(y = "none") + #' coord_cartesian(clip = "off") + #' theme_ridges(grid = FALSE) #' @importFrom stats quantile #' @export stat_binline <- function(mapping = NULL, data = NULL, geom = "density_ridges", position = "identity", ..., binwidth = NULL, bins = NULL, center = NULL, boundary = NULL, breaks = NULL, closed = c("right", "left"), pad = TRUE, draw_baseline = TRUE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) { layer( data = data, mapping = mapping, stat = StatBinline, geom = geom, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( binwidth = binwidth, bins = bins, center = center, boundary = boundary, breaks = breaks, closed = closed, pad = pad, draw_baseline = draw_baseline, na.rm = na.rm, ... ) ) } #' @rdname stat_binline #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto StatBin #' @export StatBinline <- ggproto("StatBinline", StatBin, required_aes = "x", default_aes = aes(height = ..density..), setup_params = function(data, params) { # provide default value if not given, happens when stat is called from a geom if (is.null(params$pad)) { params$pad <- TRUE } # provide default value if not given, happens when stat is called from a geom if (is.null(params$draw_baseline)) { params$draw_baseline <- TRUE } if (!is.null(params$boundary) && !is.null(params$center)) { stop("Only one of `boundary` and `center` may be specified.", call. = FALSE) } if (is.null(params$breaks) && is.null(params$binwidth) && is.null(params$bins)) { message("`stat_binline()` using `bins = 30`. Pick better value with `binwidth`.") params$bins <- 30 } params }, compute_group = function(self, data, scales, binwidth = NULL, bins = NULL, center = NULL, boundary = NULL, closed = c("right", "left"), pad = TRUE, breaks = NULL, origin = NULL, right = NULL, drop = NULL, width = NULL, draw_baseline = TRUE) { binned <- ggproto_parent(StatBin, self)$compute_group(data = data, scales = scales, binwidth = binwidth, bins = bins, center = center, boundary = boundary, closed = closed, pad = pad, breaks = breaks) result <- rbind(transform(binned, x=xmin), transform(binned, x=xmax-0.00001*width)) result <- result[order(result$x), ] # remove zero counts if requested if (!draw_baseline) { zeros <- result$count == 0 protected <- (zeros & !c(zeros[2:length(zeros)], TRUE)) | (zeros & !c(TRUE, zeros[1:length(zeros)-1])) to_remove <- zeros & !protected result$count[to_remove] <- NA result$density[to_remove] <- NA } result } ) ggridges/R/geomsv.R0000644000176200001440000002016213606371763013706 0ustar liggesusers#' Plot a vertical ridgeline (ridgeline rotated 90 degrees) #' #' Plots the sum of the `x` and `width` aesthetics versus `y`, filling the area between `x` and `x + width` with a color. #' Just like [geom_ridgeline()], but with y and x replaced. #' #' @param mapping Set of aesthetic mappings created by [`aes()`] or #' [`aes_()`]. If specified and `inherit.aes = TRUE` (the #' default), it is combined with the default mapping at the top level of the #' plot. You must supply `mapping` if there is no plot mapping. #' @param data The data to be displayed in this layer. There are three #' options: #' #' If `NULL`, the default, the data is inherited from the plot #' data as specified in the call to [`ggplot()`]. #' #' A `data.frame`, or other object, will override the plot #' data. #' #' A `function` will be called with a single argument, #' the plot data. The return value must be a `data.frame.`, and #' will be used as the layer data. #' @param stat The statistical transformation to use on the data for this #' layer, as a string. #' @param position Position adjustment, either as a string, or the result of #' a call to a position adjustment function. #' @param show.legend logical. Should this layer be included in the legends? #' `NA`, the default, includes if any aesthetics are mapped. #' `FALSE` never includes, and `TRUE` always includes. #' @param inherit.aes If `FALSE`, overrides the default aesthetics, #' rather than combining with them. #' @param na.rm If `FALSE`, the default, missing values are removed with #' a warning. If `TRUE`, missing values are silently removed. #' @param ... other arguments passed on to [`layer()`]. These are #' often aesthetics, used to set an aesthetic to a fixed value, like #' `color = "red"` or `size = 3`. They may also be parameters #' to the paired geom/stat. #' #' @section Aesthetics: #' #' Required aesthetics are in bold. #' #' * **`x`** #' * **`y`** #' * **`width`** Width of the ridgeline, measured from the respective `x` value. Assumed to be positive, though this is not required. #' * `group` Defines the grouping. Required when the dataset contains multiple distinct ridgelines. Will typically be the same #' variable as is mapped to `x`. #' * `scale` A scaling factor to scale the widths of the ridgelines. #' A value of 1 indicates that the widths are taken as is. This aesthetic can be used to convert #' `width` units into `x` units. #' * `min_width` A width cutoff on the drawn ridgelines. All values that fall below this cutoff will be removed. #' The main purpose of this cutoff is to remove long tails right at the baseline level, but other uses are possible. #' The cutoff is applied before any width #' scaling is applied via the `scale` aesthetic. Default is 0, so negative values are removed. #' * `color` Color of the ridgeline #' * `fill` Fill color of the area under the ridgeline #' * `alpha` Transparency level of `fill`. Not applied to `color`. If you want transparent lines, you can set their #' color as RGBA value, e.g. #FF0000A0 for partially transparent red. #' * `group` Grouping, to draw multiple ridgelines from one dataset #' * `linetype` Linetype of the ridgeline #' * `size` Line thickness #' #' @examples #' library(ggplot2) #' #' d <- data.frame(y = rep(1:5, 3), x = c(rep(0, 5), rep(1, 5), rep(3, 5)), #' width = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) #' ggplot(d, aes(x, y, width = width, group = x)) + geom_vridgeline(fill="lightblue") #' #' ggplot(iris, aes(x=Species, y=Sepal.Width, width = ..density.., fill=Species)) + #' geom_vridgeline(stat="ydensity", trim=FALSE, alpha = 0.85, scale = 2) #' #' @importFrom ggplot2 layer #' @export geom_vridgeline <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ...) { layer( data = data, mapping = mapping, stat = stat, geom = GeomVRidgeline, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, ... ) ) } #' @rdname geom_vridgeline #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto Geom draw_key_polygon #' @importFrom plyr summarise #' @export GeomVRidgeline <- ggproto("GeomVRidgeline", Geom, default_aes = aes(color = "black", fill = "grey80", x = 0, size = 0.5, linetype = 1, min_width = 0, scale = 1, alpha = NA), required_aes = c("x", "y", "width"), setup_data = function(self, data, params) { if (!"scale" %in% names(data)) { if (!"scale" %in% names(params)) data <- cbind(data, scale = self$default_aes$scale) else data <- cbind(data, scale = params$scale) } if (!"min_width" %in% names(data)){ if (!"min_width" %in% names(params)) data <- cbind(data, min_width = self$default_aes$min_width) else data <- cbind(data, min_width = params$min_width) } transform(data, xmin = x, xmax = x + scale*width) }, draw_key = draw_key_polygon, handle_na = function(data, params) { data }, draw_panel = function(self, data, panel_params, coord, ...) { groups <- split(data, factor(data$group)) # sort list so highest xmin values are in the front # we take a shortcut here and look only at the first xmin value given o <- order(unlist(lapply(groups, function(data){data$xmin[1]})), decreasing = TRUE) groups <- groups[o] grobs <- lapply(groups, function(group) { self$draw_group(group, panel_params, coord, ...) }) ggname(snake_class(self), gTree( children = do.call("gList", grobs) )) }, draw_group = function(self, data, panel_params, coord, na.rm = FALSE) { if (na.rm) data <- data[stats::complete.cases(data[c("y", "xmin", "xmax")]), ] #if dataframe is empty there's nothing to draw if (nrow(data) == 0) return(grid::nullGrob()) data <- data[order(data$group, data$y), ] # remove all points that fall below the minimum width data$xmax[data$width < data$min_width] <- NA # Check that aesthetics are constant aes <- unique(data[c("colour", "fill", "size", "linetype", "alpha")]) if (nrow(aes) > 1) { stop("Aesthetics can not vary along a ridgeline") } aes <- as.list(aes) # Instead of removing NA values from the data and plotting a single # polygon, we want to "stop" plotting the polygon whenever we're # missing values and "start" a new polygon as soon as we have new # values. We do this by creating an id vector for polygonGrob that # has distinct polygon numbers for sequences of non-NA values and NA # for NA values in the original data. Example: c(NA, 2, 2, 2, NA, NA, # 4, 4, 4, NA) missing_pos <- !stats::complete.cases(data[c("y", "xmin", "xmax")]) ids <- cumsum(missing_pos) + 1 ids[missing_pos] <- NA # munching for polygon positions <- plyr::summarise(data, y = c(y, rev(y)), x = c(xmax, rev(xmin)), id = c(ids, rev(ids))) munched_poly <- ggplot2::coord_munch(coord, positions, panel_params) # munching for line positions <- plyr::summarise(data, y = y, x = xmax, id = ids) munched_line <- ggplot2::coord_munch(coord, positions, panel_params) # placing the actual grob generation into a separate function allows us to override for geom_density_ridges2 self$make_group_grob(munched_line, munched_poly, aes) }, make_group_grob = function(munched_line, munched_poly, aes) { lg <- ggname("geom_ridgeline", grid::polylineGrob( munched_line$x, munched_line$y, id = munched_line$id, default.units = "native", gp = grid::gpar( col = aes$colour, lwd = aes$size * .pt, lty = aes$linetype) )) ag <- ggname("geom_ridgeline", grid::polygonGrob( munched_poly$x, munched_poly$y, id = munched_poly$id, default.units = "native", gp = grid::gpar( fill = ggplot2::alpha(aes$fill, aes$alpha), lty = 0) )) grid::grobTree(ag, lg) } ) ggridges/R/position.R0000644000176200001440000001644013606436121014244 0ustar liggesusers#' Randomly jitter the points in a ridgeline plot #' #' This is a position adjustment specifically for [`geom_density_ridges()`] and related geoms. It #' only jitters the points drawn by these geoms, if any. If no points are present, the plot #' remains unchanged. The effect is similar to [`position_jitter()`]: points are randomly shifted up and down #' and/or left and right. #' #' @param width Width for horizontal jittering. By default set to 0. #' @param height Height for vertical jittering, applied in both directions (up and down). By default 0.2. #' @param yoffset Vertical offset applied in addition to jittering. #' @param adjust_vlines If `TRUE`, adjusts vertical lines (as are drawn for #' quantile lines, for example) to align with the point cloud. #' @param seed Random seed. If set to NULL, the current random number generator is used. #' If set to NA, a new random random seed is generated. If set to a number, this #' number is used as seed for jittering only. #' @seealso Other position adjustments for ridgeline plots: [`position_points_sina`], [`position_raincloud`] #' @examples #' library(ggplot2) #' #' # default jittered points #' ggplot(iris, aes(x = Sepal.Length, y = Species)) + #' geom_density_ridges(jittered_points = TRUE, position = "points_jitter", alpha = 0.7) #' #' # simulating a rug #' ggplot(iris, aes(x = Sepal.Length, y = Species)) + #' geom_density_ridges(jittered_points = TRUE, point_shape = '|', alpha = 0.7, point_size = 2, #' position = position_points_jitter(width = 0.02, height = 0)) #' @export position_points_jitter <- function(width = 0, height = 0.2, yoffset = 0, adjust_vlines = FALSE, seed = NULL) { if (!is.null(seed) && is.na(seed)) { seed <- sample.int(.Machine$integer.max, 1L) } ggproto(NULL, PositionPointsJitter, width = width, height = height, yoffset = yoffset, adjust_vlines = adjust_vlines, seed = seed ) } #' @rdname position_points_jitter #' @format NULL #' @usage NULL #' @export PositionPointsJitter <- ggproto("PositionPointsJitter", Position, required_aes = c("x", "ymin", "ymax"), setup_params = function(self, data) { list( width = self$width %||% 0, height = self$height %||% 0.2, yoffset = self$yoffset %||% 0, adjust_vlines = self$adjust_vlines %||% FALSE, seed = self$seed ) }, compute_layer = function(data, params, panel) { # if there's no datatype aesthetic then we're done by default if (!"datatype" %in% names(data)) { return(data) } points <- data$datatype == "point" with_seed_null(params$seed, { if (params$width > 0) { data$x[points] <- data$x[points] - params$width + 2 * params$width * runif(sum(points)) }; data$ymin[points] <- data$ymin[points] + params$yoffset - params$height + 2 * params$height * runif(sum(points)) }) # do we need to adjust vertical lines as well? if (!params$adjust_vlines) { return(data) # no, we're done } vlines <- data$datatype == "vline" data$ymin[vlines] <- data$ymin[vlines] + params$yoffset - params$height data$ymax[vlines] <- data$ymin[vlines] + 2 * params$height data } ) #' Create a cloud of randomly jittered points below a ridgeline plot #' #' This is a position adjustment specifically for [`geom_density_ridges()`] and related geoms. It #' only jitters the points drawn by these geoms, if any. If no points are present, the plot #' remains unchanged. The effect is similar to [`position_points_jitter()`], only that by default the #' points lie all underneath the baseline of each individual ridgeline. #' #' The idea for this position adjustment comes from Micah Allen, who proposed this type of plot in #' a [blog post](https://micahallen.org/2018/03/15/introducing-raincloud-plots/) on March 15, 2018. #' #' @param width Width for horizontal jittering. By default set to 0. #' @param height Total height of point cloud. By default 0.4. #' @param ygap Vertical gap between ridgeline baseline and point cloud. #' @param adjust_vlines If `TRUE`, adjusts vertical lines (as are drawn for #' quantile lines, for example) to align with the point cloud. #' @param seed Random seed. See [`position_points_jitter`]. #' @seealso Other position adjustments for ridgeline plots: [`position_points_jitter`], [`position_points_sina`] #' @examples #' library(ggplot2) #' #' ggplot(iris, aes(x = Sepal.Length, y = Species)) + #' geom_density_ridges(jittered_points = TRUE, position = "raincloud", alpha = 0.7) #' @export position_raincloud <- function(width = 0, height = 0.4, ygap = 0.05, adjust_vlines = FALSE, seed = NULL) { if (!is.null(seed) && is.na(seed)) { seed <- sample.int(.Machine$integer.max, 1L) } ggproto(NULL, PositionRaincloud, width = width, height = height, ygap = ygap, adjust_vlines = adjust_vlines, seed = seed ) } #' @rdname position_raincloud #' @format NULL #' @usage NULL #' @export PositionRaincloud <- ggproto("PositionRaincloud", PositionPointsJitter, required_aes = c("x", "ymin", "ymax"), setup_params = function(self, data) { height <- (self$height %||% 0.4)/2 yoffset <- -height - (self$ygap %||% 0.05) list( width = self$width %||% 0, height = height, yoffset = yoffset, adjust_vlines = self$adjust_vlines %||% FALSE, seed = self$seed ) } ) #' Randomly distribute points in a ridgeline plot between baseline and ridgeline #' #' This is a position adjustment specifically for [`geom_density_ridges()`] and related geoms. It #' only jitters the points drawn by these geoms, if any. If no points are present, the plot #' remains unchanged. The effect is similar to a sina plot: Points are randomly distributed to fill #' the entire shaded area representing the data density. #' #' @param rel_min The relative minimum value at which a point can be placed. #' @param rel_max The relative maximum value at which a point can be placed. #' @param seed See [`position_points_jitter`]. #' @seealso Other position adjustments for ridgeline plots: [`position_points_jitter`], [`position_raincloud`] #' @examples #' library(ggplot2) #' #' ggplot(iris, aes(x = Sepal.Length, y = Species)) + #' geom_density_ridges(jittered_points = TRUE, position = "points_sina", alpha = 0.7) #' @export position_points_sina <- function(rel_min = 0.02, rel_max = 0.98, seed = NULL) { if (!is.null(seed) && is.na(seed)) { seed <- sample.int(.Machine$integer.max, 1L) } ggproto(NULL, PositionPointsSina, rel_min = rel_min, rel_max = rel_max, seed = seed ) } #' @rdname position_points_sina #' @format NULL #' @usage NULL #' @export PositionPointsSina <- ggproto("PositionPointsSina", Position, required_aes = c("x", "ymin", "ymax"), setup_params = function(self, data) { list( rel_min = self$rel_abc %||% 0.02, rel_max = self$rel_max %||% 0.98, seed = self$seed ) }, compute_layer = function(data, params, panel) { # if there's no datatype aesthetic then we're done by default if (!"datatype" %in% names(data)) { return(data) } points <- data$datatype == "point" with_seed_null(params$seed, data$ymin[points] <- data$ymin[points] + (params$rel_min + (params$rel_max - params$rel_min) * runif(sum(points))) * (data$ymax[points] - data$ymin[points]) ) data } ) ggridges/R/data.R0000644000176200001440000000440713606377513013322 0ustar liggesusers#' Weather in Lincoln, Nebraska in 2016. #' #' A dataset containing weather information from Lincoln, Nebraska, from 2016. #' Originally downloaded from Weather Underground by Austin Wehrwein, http://austinwehrwein.com/. #' The variables are listed below. Most are self-explanatory. Max, mean, and min measurements are #' calculated relative to the specific day of measurement. #' #' @format A tibble with 366 rows and 24 variables: #' \describe{ #' \item{`CST`}{Day of the measurement} #' \item{`Max Temperature [F]`}{} #' \item{`Mean Temperature [F]`}{} #' \item{`Min Temperature [F]`}{} #' \item{`Max Dew Point [F]`}{} #' \item{`Mean Dew Point [F]`}{} #' \item{`Min Dewpoint [F]`}{} #' \item{`Max Humidity`}{} #' \item{`Mean Humidity`}{} #' \item{`Min Humidity`}{} #' \item{`Max Sea Level Pressure [In]`}{} #' \item{`Mean Sea Level Pressure [In]`}{} #' \item{`Min Sea Level Pressure [In]`}{} #' \item{`Max Visibility [Miles]`}{} #' \item{`Mean Visibility [Miles]`}{} #' \item{`Min Visibility [Miles]`}{} #' \item{`Max Wind Speed [MPH]`}{} #' \item{`Mean Wind Speed[MPH]`}{} #' \item{`Max Gust Speed [MPH]`}{} #' \item{`Precipitation [In]`}{} #' \item{`CloudCover`}{} #' \item{`Events`}{Specific weather events, such as rain, snow, or fog} #' \item{`WindDir [Degrees]`}{} #' \item{`Month`}{The month in which the measurement was taken} #' } "lincoln_weather" #' Results from Catalan regional elections (1980-2015) #' #' Data from Catalan regional elections for 949 municipalities, from 11 elections spanning the years #' 1980-2015. The data was obtained and processed from Idescat.cat by Marc Belzunces (Twitter: @marcbeldata). #' @format A tibble with 20764 rows and 4 variables: #' \describe{ #' \item{`Municipality`}{} #' \item{`Year`}{} #' \item{`Option`}{The voter option; either "Indy" or "Unionist"} #' \item{`Percent`}{The percentage of the voters choosing the given option} #' } "Catalan_elections" #' Australian athletes #' #' This dataset is equivalent to `ais` from the `DAAG` package. #' #' @references #' Telford, R.D. and Cunningham, R.B. 1991. Sex, sport and body-size dependency of hematology in #' highly trained athletes. Medicine and Science in Sports and Exercise 23: 788-794. #' #' @examples #' # none yet "Aus_athletes" ggridges/R/scale-point.R0000644000176200001440000001212713606371763014626 0ustar liggesusers#' Scales for point aesthetics #' #' These are various scales that can be applied to point aesthetics, such as #' `point_color`, `point_fill`, `point_size`. The individual scales all have the #' same usage as existing standard ggplot2 scales, only the name differs. #' #' @name scale_point #' @seealso See [`scale_vline_color_hue()`] for specific scales for vline aesthetics #' and [`scale_discrete_manual()`] for a general discrete scale. #' @examples #' library(ggplot2) #' #' # default scales #' ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species)) + #' geom_density_ridges( #' aes( #' point_color = Species, point_fill = Species, #' point_shape = Species #' ), #' alpha = .4, jittered_points = TRUE #' ) + #' theme_ridges() #' #' # modified scales #' ggplot(iris, aes(x=Sepal.Length, y=Species, fill = Species)) + #' geom_density_ridges( #' aes( #' point_color = Species, point_fill = Species, #' point_shape = Species #' ), #' alpha = .4, point_alpha = 1, #' jittered_points = TRUE #' ) + #' scale_fill_hue(l = 50) + #' scale_point_color_hue(l = 20) + #' scale_point_fill_hue(l = 70) + #' scale_discrete_manual("point_shape", values = c(21, 22, 23)) + #' theme_ridges() #' @aliases NULL NULL #' `scale_point_shape()`: Equivalent to [`scale_shape()`]. #' @rdname scale_point #' @usage NULL #' @export scale_point_shape <- function(..., solid = TRUE, aesthetics = "point_shape") { discrete_scale(aesthetics, "shape_d", scales::shape_pal(solid), ...) } #' `scale_point_size_continuous()`: Equivalent to [`scale_size_continuous()`]. #' @rdname scale_point #' @usage NULL #' @export scale_point_size_continuous <- function(name = ggplot2::waiver(), breaks = ggplot2::waiver(), labels = ggplot2::waiver(), limits = NULL, range = c(1, 6), trans = "identity", guide = "legend", aesthetics = "point_size") { ggplot2::continuous_scale(aesthetics, "area", scales::area_pal(range), name = name, breaks = breaks, labels = labels, limits = limits, trans = trans, guide = guide) } #' `scale_point_colour_hue()`: Equivalent to [`scale_colour_hue()`]. #' @rdname scale_point #' @usage NULL #' @export scale_point_colour_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1, na.value = "grey50", aesthetics = "point_colour") { ggplot2::discrete_scale(aesthetics, "hue", scales::hue_pal(h, c, l, h.start, direction), na.value = na.value, ...) } #' @rdname scale_point #' @usage NULL #' @export scale_point_color_hue <- function(..., h = c(0, 360) + 15, c = 100, l = 65, h.start = 0, direction = 1, na.value = "grey50", aesthetics = "point_color") { ggplot2::discrete_scale(aesthetics, "hue", scales::hue_pal(h, c, l, h.start, direction), na.value = na.value, ...) } #' `scale_point_fill_hue()`: Equivalent to [`scale_fill_hue()`]. #' @rdname scale_point #' @usage NULL #' @export scale_point_fill_hue <- function(...) scale_point_color_hue(..., aesthetics = "point_fill") #' `scale_point_colour_gradient()`: Equivalent to [`scale_colour_gradient()`]. #' @rdname scale_point #' @usage NULL #' @export scale_point_colour_gradient <- function(..., low = "#132B43", high = "#56B1F7", space = "Lab", na.value = "grey50", guide = "none", aesthetics = "point_colour") { ggplot2::continuous_scale(aesthetics, "gradient", scales::seq_gradient_pal(low, high, space), na.value = na.value, guide = guide, ...) } #' @rdname scale_point #' @usage NULL #' @export scale_point_color_gradient <- function(..., low = "#132B43", high = "#56B1F7", space = "Lab", na.value = "grey50", guide = "none", aesthetics = "point_color") { ggplot2::continuous_scale(aesthetics, "gradient", scales::seq_gradient_pal(low, high, space), na.value = na.value, guide = guide, ...) } #' `scale_point_fill_gradient()`: Equivalent to [`scale_fill_gradient()`]. Note that this scale cannot #' draw a legend, however, because of limitations in [`guide_colorbar()`]. #' @rdname scale_point #' @usage NULL #' @export scale_point_fill_gradient <- function(...) scale_point_color_gradient(..., aesthetics = "point_fill") # default scales #' @rdname scale_point #' @usage NULL #' @export scale_point_shape_discrete <- scale_point_shape #' @rdname scale_point #' @usage NULL #' @export scale_point_color_discrete <- scale_point_color_hue #' @rdname scale_point #' @usage NULL #' @export scale_point_colour_discrete <- scale_point_colour_hue #' @rdname scale_point #' @usage NULL #' @export scale_point_fill_discrete <- scale_point_fill_hue #' @rdname scale_point #' @usage NULL #' @export scale_point_color_continuous <- scale_point_color_gradient #' @rdname scale_point #' @usage NULL #' @export scale_point_colour_continuous <- scale_point_colour_gradient #' @rdname scale_point #' @usage NULL #' @export scale_point_fill_continuous <- scale_point_fill_gradient ggridges/R/scale-cyclical.R0000644000176200001440000001167613606371763015270 0ustar liggesusers#' Create a discrete scale that cycles between values #' #' The readability of ridgeline plots can often be improved by alternating between fill colors and #' other aesthetics. The various cyclical scales make it easy to create plots with this feature, #' simply map your grouping variable to the respective aesthetic (e.g., `fill`) and then use #' `scale_fill_cyclical` to define the fill colors between you want to alternate. Note that the #' cyclical scales do not draw legends by default, because the legends will usually be wrong #' unless the labels are properly adjusted. To draw legends, set the `guide` argument to `"legend"`, #' as shown in the examples. #' #' @param values The aesthetic values that the scale should cycle through, e.g. colors if it is #' a scale for the color or fill aesthetic. #' @param ... Common discrete scale parameters: `name`, `breaks`, `labels`, `na.value`, `limits` and `guide`. #' See [`discrete_scale`] for more details. #' #' @examples #' library(ggplot2) #' #' # By default, scale_cyclical sets `guide = "none"`, i.e., no legend #' # is drawn #' ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + #' geom_density_ridges(scale = 4) + #' scale_fill_cyclical(values = c("#3030D0", "#9090F0")) #' #' # However, legends can be turned on by setting `guide = "legend"` #' ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + #' geom_density_ridges(scale = 4) + #' scale_fill_cyclical(values = c("#3030D0", "#9090F0"), #' guide = "legend", name = "Fill colors", #' labels = c("dark blue", "light blue")) #' #' # Cyclical scales are also available for the various other aesthetics #' ggplot(diamonds, aes(x = price, y = cut, fill = cut, #' color = cut, size = cut, #' alpha = cut, linetype = cut)) + #' geom_density_ridges(scale = 4, fill = "blue") + #' scale_fill_cyclical(values = c("blue", "green")) + #' scale_color_cyclical(values = c("black", "white")) + #' scale_size_cyclical(values = c(2, 1)) + #' scale_alpha_cyclical(values = c(0.4, 0.8)) + #' scale_linetype_cyclical(values = c(1, 2)) #' #' @name scale_cyclical #' @aliases NULL NULL #' @rdname scale_cyclical #' @export scale_colour_cyclical <- function(..., values) { cyclical_scale("colour", values, ...) } #' @rdname scale_cyclical #' @export #' @usage NULL scale_color_cyclical <- scale_colour_cyclical #' @rdname scale_cyclical #' @export scale_fill_cyclical <- function(..., values) { cyclical_scale("fill", values, ...) } #' @rdname scale_cyclical #' @export scale_alpha_cyclical <- function(..., values) { cyclical_scale("alpha", values, ...) } #' @rdname scale_cyclical #' @export scale_linetype_cyclical <- function(..., values) { cyclical_scale("linetype", values, ...) } #' @rdname scale_cyclical #' @export scale_size_cyclical <- function(..., values) { cyclical_scale("size", values, ...) } #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto ScaleDiscrete #' @rdname scale_cyclical #' @export cyclical_scale <- function(aesthetics, values, name = waiver(), breaks = waiver(), labels = waiver(), limits = NULL, expand = waiver(), na.translate = TRUE, na.value = NA, drop = TRUE, guide = "none", position = "left") { check_breaks_labels(breaks, labels) position <- match.arg(position, c("left", "right", "top", "bottom")) if (is.null(breaks) && !is_position_aes(aesthetics) && guide != "none") { guide <- "none" } # palette function pal <- function(n) { rep_len(values, n) } ggproto(NULL, ScaleCyclical, # standard fields of ScaleDiscrete call = match.call(), aesthetics = aesthetics, scale_name = "cyclical", palette = pal, range = discrete_range(), limits = limits, na.value = na.value, na.translate = na.translate, expand = expand, name = name, breaks = breaks, labels = labels, drop = drop, guide = guide, position = position, # new fields for ScaleCyclical cycle_length = length(values) ) } #' @rdname scale_cyclical #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto ScaleDiscrete #' @export ScaleCyclical <- ggproto("ScaleCyclical", ScaleDiscrete, get_breaks = function(self, limits = self$get_limits()){ breaks <- ggproto_parent(ScaleDiscrete, self)$get_breaks(limits) return(na.omit(breaks[1:self$cycle_length])) }, get_labels = function(self, breaks = self$get_breaks()){ labels <- ggproto_parent(ScaleDiscrete, self)$get_labels(breaks) return(na.omit(labels[1:self$cycle_length])) } ) # internal functions, copied over from ggplot2 check_breaks_labels <- function(breaks, labels) { if (is.null(breaks)) return(TRUE) if (is.null(labels)) return(TRUE) bad_labels <- is.atomic(breaks) && is.atomic(labels) && length(breaks) != length(labels) if (bad_labels) { stop("`breaks` and `labels` must have the same length", call. = FALSE) } TRUE } ggridges/R/geom-density-line.R0000644000176200001440000000357413606371763015747 0ustar liggesusers#' Smoothed density estimates drawn with a ridgeline rather than area #' #' This function is a drop-in replacement for ggplot2's [geom_density()]. The only difference is that #' the geom draws a ridgeline (line with filled area underneath) rather than a polygon. #' #' @seealso See [geom_density()]. #' @importFrom ggplot2 layer #' @importFrom ggplot2 geom_density #' @inheritParams ggplot2::layer #' @inheritParams ggplot2::geom_density #' @export #' @examples #' library(ggplot2) #' ggplot(diamonds, aes(carat)) + #' geom_density_line() #' #' ggplot(diamonds, aes(carat)) + #' geom_density_line(adjust = 1/5) #' ggplot(diamonds, aes(carat)) + #' geom_density_line(adjust = 5) #' #' ggplot(diamonds, aes(depth, colour = cut)) + #' geom_density_line(alpha = 0.5) + #' xlim(55, 70) #' ggplot(diamonds, aes(depth, fill = cut, colour = cut)) + #' geom_density_line(alpha = 0.1) + #' xlim(55, 70) geom_density_line <- function(mapping = NULL, data = NULL, stat = "density", position = "identity", ..., na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) { layer( data = data, mapping = mapping, stat = stat, geom = GeomDensityLine, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, ... ) ) } #' @rdname geom_density_line #' @format NULL #' @usage NULL #' @export GeomDensityLine <- ggproto("GeomDensityLine", GeomRidgeline, required_aes = c("x", "y"), setup_data = function(self, data, params) { if (!"min_height" %in% names(data)){ if (!"min_height" %in% names(params)) data <- cbind(data, min_height = self$default_aes$min_height) else data <- cbind(data, min_height = params$min_height) } transform(data, ymin = 0, ymax = y) } ) ggridges/R/ggridges.R0000644000176200001440000000035513606371763014203 0ustar liggesusers#' Ridgeline plots with ggplot2 #' #' Please see the package vignettes for usage instructions. For a quick start, #' check out the examples for [`geom_density_ridges()`]. #' #' @name ggridges #' @docType package #' @import ggplot2 NULL ggridges/R/geoms-gradient.R0000644000176200001440000004244413606411204015303 0ustar liggesusers#' Plot ridgelines and ridgeline plots with fill gradients along the x axis #' #' The geoms `geom_ridgeline_gradient` and `geom_density_ridges_gradient` work just like [`geom_ridgeline`] and [`geom_density_ridges`] except #' that the `fill` aesthetic can vary along the x axis. Because filling with color gradients is fraught with issues, #' these geoms should be considered experimental. Don't use them unless you really need to. Note that due to limitations #' in R's graphics system, transparency (`alpha`) has to be disabled for gradient fills. #' #' @param mapping Set of aesthetic mappings created by [`aes()`] or #' [`aes_()`]. If specified and `inherit.aes = TRUE` (the #' default), it is combined with the default mapping at the top level of the #' plot. You must supply `mapping` if there is no plot mapping. #' @param data The data to be displayed in this layer. There are three #' options: #' #' If `NULL`, the default, the data is inherited from the plot #' data as specified in the call to [`ggplot()`]. #' #' A `data.frame`, or other object, will override the plot #' data. #' #' A `function` will be called with a single argument, #' the plot data. The return value must be a `data.frame.`, and #' will be used as the layer data. #' @param stat The statistical transformation to use on the data for this #' layer, as a string. #' @param position Position adjustment, either as a string, or the result of #' a call to a position adjustment function. #' @param show.legend logical. Should this layer be included in the legends? #' `NA`, the default, includes if any aesthetics are mapped. #' `FALSE` never includes, and `TRUE` always includes. #' @param inherit.aes If `FALSE`, overrides the default aesthetics, #' rather than combining with them. #' @param na.rm If `FALSE`, the default, missing values are removed with #' a warning. If `TRUE`, missing values are silently removed. #' @param gradient_lwd A parameter to needed to remove rendering artifacts inside the #' rendered gradients. Should ideally be 0, but often needs to be around 0.5 or higher. #' @param ... other arguments passed on to [`layer()`]. These are #' often aesthetics, used to set an aesthetic to a fixed value, like #' `color = "red"` or `size = 3`. They may also be parameters #' to the paired geom/stat. #' #' @examples #' library(ggplot2) #' #' # Example for `geom_ridgeline_gradient()` #' d <- data.frame( #' x = rep(1:5, 3) + c(rep(0, 5), rep(0.3, 5), rep(0.6, 5)), #' y = c(rep(0, 5), rep(1, 5), rep(3, 5)), #' height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1) #' ) #' ggplot(d, aes(x, y, height = height, group = y, fill = factor(x+y))) + #' geom_ridgeline_gradient() + #' scale_fill_viridis_d(direction = -1) + #' theme(legend.position = 'none') #' @importFrom ggplot2 layer #' @export geom_ridgeline_gradient <- function(mapping = NULL, data = NULL, stat = "identity", position = "identity", na.rm = FALSE, gradient_lwd = 0.5, show.legend = NA, inherit.aes = TRUE, ...) { layer( data = data, mapping = mapping, stat = stat, geom = GeomRidgelineGradient, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, gradient_lwd = gradient_lwd, ... ) ) } #' @rdname geom_ridgeline_gradient #' @format NULL #' @usage NULL #' @importFrom ggplot2 ggproto Geom draw_key_polygon #' @export GeomRidgelineGradient <- ggproto("GeomRidgelineGradient", Geom, default_aes = aes( # ridgeline aesthetics color = "black", fill = "grey70", y = 0, size = 0.5, linetype = 1, min_height = 0, scale = 1, alpha = NA, datatype = "ridgeline", # point aesthetics with default point_shape = 19, point_size = 1.5, point_stroke = 0.5, # point aesthetics, inherited point_colour = NULL, #point_color = NULL, point_fill = NULL, point_alpha = NULL, # vline aesthetics, all inherited vline_colour = NULL, #vline_color = NULL, vline_size = NULL, vline_linetype = NULL ), required_aes = c("x", "y", "height"), optional_aes = c("point_color", "vline_color"), extra_params = c("na.rm", "jittered_points"), setup_data = function(self, data, params) { if (!"scale" %in% names(data)) { if (!"scale" %in% names(params)) data <- cbind(data, scale = self$default_aes$scale) else data <- cbind(data, scale = params$scale) } if (!"min_height" %in% names(data)){ if (!"min_height" %in% names(params)) data <- cbind(data, min_height = self$default_aes$min_height) else data <- cbind(data, min_height = params$min_height) } transform(data, ymin = y, ymax = y + scale*height) }, draw_key = function(data, params, size) { lwd <- min(data$size, min(size) / 4) rect_grob <- grid::rectGrob( width = grid::unit(1, "npc") - grid::unit(lwd, "mm"), height = grid::unit(1, "npc") - grid::unit(lwd, "mm"), gp = grid::gpar( col = data$colour, fill = data$fill, lty = data$linetype, lwd = lwd * .pt, linejoin = "mitre" )) # if vertical lines were drawn then we need to add them to the legend also if (is.null(params$quantile_lines) || !params$quantile_lines) { vlines_grob <- grid::nullGrob() } else { vlines_grob <- grid::segmentsGrob(0.5, 0.1, 0.5, 0.9, gp = grid::gpar( col = data$vline_colour %||% data$vline_color %||% data$colour, lwd = (data$vline_size %||% data$size) * .pt, lty = data$vline_linetype %||% data$linetype, lineend = "butt" ) ) } # if jittered points were drawn then we need to add them to the legend also if (is.null(params$jittered_points) || !params$jittered_points) { point_grob <- grid::nullGrob() } else { point_grob <- grid::pointsGrob(0.5, 0.5, pch = data$point_shape, gp = grid::gpar( col = alpha( data$point_colour %||% data$point_color %||% data$colour, data$point_alpha %||% data$alpha ), fill = alpha( data$point_fill %||% data$fill, data$point_alpha %||% data$alpha ), fontsize = data$point_size * .pt + data$point_stroke * .stroke / 2, lwd = data$point_stroke * .stroke / 2 ) ) } grid::grobTree(rect_grob, vlines_grob, point_grob) }, handle_na = function(data, params) { data }, draw_panel = function(self, data, panel_params, coord, ...) { groups <- split(data, factor(data$group)) # sort list so highest ymin values are in the front # we take a shortcut here and look only at the first ymin value given o <- order(unlist(lapply(groups, function(data){data$ymin[1]})), decreasing = TRUE) groups <- groups[o] grobs <- lapply(groups, function(group) { self$draw_group(group, panel_params, coord, ...) }) ggname(snake_class(self), gTree( children = do.call("gList", grobs) )) }, draw_group = function(self, data, panel_params, coord, na.rm = FALSE, gradient_lwd = 0.5) { if (na.rm) data <- data[stats::complete.cases(data[c("x", "ymin", "ymax")]), ] # split data into data types (ridgeline, vline, point) data_list <- split(data, factor(data$datatype)) point_grob <- self$make_point_grob(data_list[["point"]], panel_params, coord) vline_grob <- self$make_vline_grob(data_list[["vline"]], panel_params, coord) data <- data_list[["ridgeline"]] # if the final data set is empty then we're done here if (is.null(data)) { return(grid::grobTree(vline_grob, point_grob)) } # otherwise, continue. First we order the data, in preparation for polygon drawing data <- data[order(data$group, data$x), ] # remove all points that fall below the minimum height data$ymax[data$height < data$min_height] <- NA # Check that aesthetics are constant aes <- unique(data[c("colour", "size", "linetype")]) if (nrow(aes) > 1) { stop("These aesthetics can not vary along a ridgeline: color, size, linetype") } aes <- as.list(aes) # Instead of removing NA values from the data and plotting a single # polygon, we want to "stop" plotting the polygon whenever we're # missing values and "start" a new polygon as soon as we have new # values. We do this by creating an id vector for polygonGrob that # has distinct polygon numbers for sequences of non-NA values and NA # for NA values in the original data. Example: c(NA, 2, 2, 2, NA, NA, # 4, 4, 4, NA) missing_pos <- !stats::complete.cases(data[c("x", "ymin", "ymax")]) ids <- cumsum(missing_pos) + 1 ids[missing_pos] <- NA data <- cbind(data, ids) data <- data[!missing_pos,] # munching for line positions <- plyr::summarise(data, x = x, y = ymax, id = ids) munched_line <- ggplot2::coord_munch(coord, positions, panel_params) # We now break down the polygons further by fill color, since # we need to draw a separate polygon for each color # calculate all the positions where the fill type changes fillchange <- c(FALSE, data$fill[2:nrow(data)] != data$fill[1:nrow(data)-1]) # and where the id changes idchange <- c(TRUE, data$ids[2:nrow(data)] != data$ids[1:nrow(data)-1]) # make new ids from all changes in fill style or original id data$ids <- cumsum(fillchange | idchange) # get fill color for all ids fill <- data$fill[fillchange | idchange] # append to aes list aes <- c(aes, list(fill=fill)) # rows to be duplicated dupl_rows <- which(fillchange & !idchange) if (length(dupl_rows)>0){ rows <- data[dupl_rows, ] rows$ids <- data$ids[dupl_rows-1] # combine original and duplicated data data <- rbind(data, rows) } # munching for polygon positions <- plyr::summarise(data, x = c(x, rev(x)), y = c(ymax, rev(ymin)), id = c(ids, rev(ids))) munched_poly <- ggplot2::coord_munch(coord, positions, panel_params) # calculate line and area grobs line_grob <- self$make_line_grob(munched_line, aes) area_grob <- self$make_area_grob(munched_poly, aes, gradient_lwd) # combine everything and return grid::grobTree(area_grob, vline_grob, line_grob, point_grob) }, make_point_grob = function(data, panel_params, coord) { if (is.null(data)) { return(grid::nullGrob()) } data$y <- data$ymin coords <- coord$transform(data, panel_params) ggname("geom_ridgeline_gradient", grid::pointsGrob( coords$x, coords$y, pch = coords$point_shape, gp = grid::gpar( col = alpha( data$point_colour %||% data$point_color %||% data$colour, data$point_alpha %||% data$alpha ), fill = alpha( data$point_fill %||% data$fill, data$point_alpha %||% data$alpha ), # Stroke is added around the outside of the point fontsize = coords$point_size * .pt + coords$point_stroke * .stroke / 2, lwd = coords$point_stroke * .stroke / 2 ) ) ) }, make_vline_grob = function(data, panel_params, coord) { if (is.null(data)) { return(grid::nullGrob()) } data$xend <- data$x data$y <- data$ymin data$yend <- data$ymax data$alpha <- NA # copy vline aesthetics over if set data$colour <- data$vline_colour %||% data$vline_color %||% data$colour data$linetype <- data$vline_linetype %||% data$linetype data$size <- data$vline_size %||% data$size ggplot2::GeomSegment$draw_panel(data, panel_params, coord) }, make_line_grob = function(munched_line, aes) { ggname("geom_ridgeline_gradient", grid::polylineGrob( munched_line$x, munched_line$y, id = munched_line$id, default.units = "native", gp = grid::gpar( col = aes$colour, lwd = aes$size * .pt, lty = aes$linetype) ) ) }, make_area_grob = function(munched_poly, aes, gradient_lwd) { ggname("geom_ridgeline_gradient", grid::polygonGrob( munched_poly$x, munched_poly$y, id = munched_poly$id, default.units = "native", gp = grid::gpar( fill = aes$fill, col = aes$fill, # we need to draw polygons with colored outlines lwd = gradient_lwd, # to prevent drawing artifacts at polygon boundaries lty = 1) ) ) }, make_group_grob_delete = function(munched_line, munched_poly, aes, gradient_lwd) { lg <- ggname("geom_ridgeline_gradient", grid::polylineGrob( munched_line$x, munched_line$y, id = munched_line$id, default.units = "native", gp = grid::gpar( col = aes$colour, lwd = aes$size * .pt, lty = aes$linetype) )) ag <- ggname("geom_ridgeline_gradient", grid::polygonGrob( munched_poly$x, munched_poly$y, id = munched_poly$id, default.units = "native", gp = grid::gpar( fill = aes$fill, col = aes$fill, # we need to draw polygons with colored outlines lwd = gradient_lwd, # to prevent drawing artifacts at polygon boundaries lty = 1) )) grid::grobTree(ag, lg) } ) #' @param panel_scaling Argument only to `geom_density_ridges_gradient`. If `TRUE`, the default, relative scaling is calculated separately #' for each panel. If `FALSE`, relative scaling is calculated globally. #' #' @rdname geom_ridgeline_gradient #' @importFrom ggplot2 layer #' @export geom_density_ridges_gradient <- function(mapping = NULL, data = NULL, stat = "density_ridges", position = "points_sina", panel_scaling = TRUE, na.rm = TRUE, gradient_lwd = 0.5, show.legend = NA, inherit.aes = TRUE, ...) { layer( data = data, mapping = mapping, stat = stat, geom = GeomDensityRidgesGradient, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( na.rm = na.rm, gradient_lwd = gradient_lwd, panel_scaling = panel_scaling, ... ) ) } #' @rdname geom_ridgeline_gradient #' @format NULL #' @usage NULL #' @importFrom grid gTree gList #' @examples #' #' # Example for `geom_density_ridges_gradient()` #' ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = `Month`, fill = stat(x))) + #' geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01) + #' scale_x_continuous(expand = c(0, 0)) + #' scale_y_discrete(expand = c(0, 0)) + #' scale_fill_viridis_c(name = "Temp. [F]", option = "C") + #' coord_cartesian(clip = "off") + #' labs(title = 'Temperatures in Lincoln NE in 2016') + #' theme_ridges(font_size = 13, grid = TRUE) + #' theme(axis.title.y = element_blank()) #' @export GeomDensityRidgesGradient <- ggproto("GeomDensityRidgesGradient", GeomRidgelineGradient, default_aes = aes( # ridgeline aesthetics color = "black", fill = "grey70", size = 0.5, linetype = 1, rel_min_height = 0, scale = 1.8, alpha = NA, datatype = "ridgeline", # point aesthetics with default point_shape = 19, point_size = 1.5, point_stroke = 0.5, # point aesthetics, inherited point_colour = NULL,# point_color = NULL, point_fill = NULL, point_alpha = NULL, # vline aesthetics, all inherited vline_colour = NULL,# vline_color = NULL, vline_size = NULL, vline_linetype = NULL ), required_aes = c("x", "y", "height"), optional_aes = c("point_color", "vline_color"), extra_params = c("na.rm", "panel_scaling", "jittered_points"), setup_data = function(self, data, params) { # provide default for panel scaling parameter if it doesn't exist, # happens if the geom is called from a stat if (is.null(params$panel_scaling)) { params$panel_scaling <- TRUE } # calculate internal scale yrange = max(data$y) - min(data$y) n = length(unique(data$y)) if (n<2) { hmax <- max(data$height, na.rm = TRUE) iscale <- 1 } else { # scale per panel or globally? if (params$panel_scaling) { heights <- split(data$height, data$PANEL) max_heights <- vapply(heights, max, numeric(1), na.rm = TRUE) hmax <- max_heights[data$PANEL] iscale <- yrange/((n-1)*hmax) } else { hmax <- max(data$height, na.rm = TRUE) iscale <- yrange/((n-1)*hmax) } } #print(iscale) #print(hmax) data <- cbind(data, iscale) if (!"scale" %in% names(data)) { if (!"scale" %in% names(params)) data <- cbind(data, scale = self$default_aes$scale) else data <- cbind(data, scale = params$scale) } if (!"rel_min_height" %in% names(data)){ if (!"rel_min_height" %in% names(params)) data <- cbind(data, rel_min_height = self$default_aes$rel_min_height) else data <- cbind(data, rel_min_height = params$rel_min_height) } transform(data, ymin = y, ymax = y + iscale*scale*height, min_height = hmax*rel_min_height) } ) ggridges/R/theme.R0000644000176200001440000001054213606436150013501 0ustar liggesusers #' A custom theme specifically for use with ridgeline plots #' #' This theme has some special modifications that make ridgeline plots look better, such as properly aligned y axis labels. #' It can draw plots with and without background grids (see examples). #' #' @param font_size Overall font size. Default is 14. #' @param font_family Default font family. #' @param line_size Default line size. #' @param grid If `TRUE` (default), a background grid is drawn. If `FALSE`, background is left empty. #' @param center_axis_labels If `TRUE`, axis labels are drawn centered. If `FALSE` (default), axis lables are #' drawn right/top-aligned. #' @return The theme. #' @examples #' library(ggplot2) #' #' # Example with background grid #' ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species)) + #' geom_density_ridges(rel_min_height = 0.005) + #' scale_y_discrete(expand = c(0.01, 0)) + #' scale_x_continuous(expand = c(0.01, 0)) + #' theme_ridges() #' #' # Example without background grid #' ggplot(iris, aes(x = Sepal.Length, y = Species, group = Species)) + #' geom_density_ridges() + #' scale_y_discrete(expand = c(0.01, 0)) + #' scale_x_continuous(expand = c(0.01, 0)) + #' theme_ridges(grid = FALSE) #' #' @export theme_ridges <- function(font_size = 14, font_family = "", line_size = .5, grid = TRUE, center_axis_labels = FALSE) { half_line <- font_size / 2 small_rel <- 0.857 small_size <- small_rel * font_size color <- "grey90" if (grid) { panel.grid.major <- element_line(colour = color, size = line_size) axis.ticks <- element_line(colour = color, size = line_size) axis.ticks.y <- axis.ticks } else { panel.grid.major <- element_blank() axis.ticks <- element_line(colour = "black", size = line_size) axis.ticks.y <- element_blank() } if (center_axis_labels) { axis_just <- 0.5 } else { axis_just <- 1.0 } theme_grey(base_size = font_size, base_family = font_family) %+replace% theme( rect = element_rect(fill = "transparent", colour = NA, color = NA, size = 0, linetype = 0), text = element_text(family = font_family, face = "plain", colour = "black", size = font_size, hjust = 0.5, vjust = 0.5, angle = 0, lineheight = .9, margin = margin(), debug = FALSE), axis.text = element_text(colour = "black", size = small_size), #axis.title = element_text(face = "bold"), axis.text.x = element_text(margin = margin(t = small_size / 4), vjust = 1), axis.text.y = element_text(margin = margin(r = small_size / 4), hjust = 1, vjust = 0), axis.title.x = element_text( margin = margin(t = small_size / 2, b = small_size / 4), hjust = axis_just ), axis.title.y = element_text( angle = 90, margin = margin(r = small_size / 2, l = small_size / 4), hjust = axis_just ), axis.ticks = axis.ticks, axis.ticks.y = axis.ticks.y, axis.line = element_blank(), legend.key = element_blank(), legend.key.size = grid::unit(1, "lines"), legend.text = element_text(size = rel(small_rel)), legend.justification = c("left", "center"), panel.background = element_blank(), panel.border = element_blank(), # make grid lines panel.grid.major = panel.grid.major, panel.grid.minor = element_blank(), strip.text = element_text(size = rel(small_rel)), strip.background = element_rect(fill = "grey80", colour = "grey50", size = 0), plot.background = element_blank(), plot.title = element_text(face = "bold", size = font_size, margin = margin(b = half_line), hjust = 0), plot.subtitle = element_text(size = rel(small_rel), hjust = 0, vjust = 1, margin = margin(b = half_line * small_rel)), plot.caption = element_text(size = rel(small_rel), hjust = 1, vjust = 1, margin = margin(t = half_line * small_rel)), plot.margin = margin(half_line, font_size, half_line, half_line), complete = TRUE ) } ggridges/NEWS.md0000644000176200001440000000573213606437275013167 0ustar liggesusersggridges 0.5.2 ---------------------------------------------------------------- - There is now a project website at https://wilkelab.org/ggridges. - A new example dataset has been added, `Aus_athletes`. - `scale_discrete_manual()` has been removed from the ggridges package, as it has been available in ggplot2 since version 3.0.0. - `stat_density_ridges()` now has a parameter `n` that determines at how many points along the x axis the density is estimated. ggridges 0.5.1 ---------------------------------------------------------------- - The `alpha` aesthetic is now by default applied to jittered points. If you don't want this to happen, set `point_alpha = 1`. - Allow custom function to calculate the position of quantile lines. This makes it possible, for example, to place a line at the mean, via `quantile_fun = mean`. - Allow coloring of quantile lines and jittered points by quantile. ggridges 0.5.0 ---------------------------------------------------------------- - Expanded documentation and gallery of example plots. - Reworked stat_density_ridges, geom_ridgeline, geom_density_ridges, etc. so that jittered points and quantile lines can be drawn on top of the distributions. Points and quantile lines can be styled separately from the rest of the ridgeline plot, via special aesthetics. - Added position options to control how the jittered points are drawn. Default is uniformly spaced within the density area. - Added `geom_density_line()` which is a drop-in replacement for `geom_density()` but draws a ridgeline rather than a closed polygon. - `theme_ridges()` has been modified so that font sizes match the cowplot themes. In particular, this means smaller axis tick labels. ggridges 0.4.1 ---------------------------------------------------------------- - Skip vdiffr visual tests when compiling on CRAN ggridges 0.4.0 ---------------------------------------------------------------- - Initial import of code base from ggjoy, and renaming: geom_joy -> geom_density_ridges stat_joy -> stat_density_ridges theme_joy -> theme_ridges ggjoy 0.3.1 ---------------------------------------------------------------- - Added an option to center axis labels to `theme_joy()`. ggjoy 0.3.0 ---------------------------------------------------------------- - Added cyclical scales that make it easy to alternate between fill colors and other aesthetics. ggjoy 0.2.0 ---------------------------------------------------------------- Numerous improvements: - New stat `binline` that can be used to draw histogram joyplots. - Various improvements in `stat_joy`. In particular, it now works properly with multiple panels. It also now has parameters `from` and `to` to limit the range of density estimation, just like `density()`. - Improvements in the vignettes - New geoms `geom_ridgeline_gradient` and `geom_joy_gradient` that can handle gradient fills. ggjoy 0.1.0 ---------------------------------------------------------------- First complete implementation ready for initial release ggridges/MD50000644000176200001440000001236613606532762012377 0ustar liggesusersea5566aebae0a3d80cbac71ab4e65010 *DESCRIPTION a23a74b3f4caf9616230789d94217acb *LICENSE bd81439439f5d51b2aae73b4051237c4 *NAMESPACE bf79a39c666204560e15e32095e48dc1 *NEWS.md 600f6c999c2a094c8459493c2afbb6ee *R/data.R f1c95d269d553f1c91c2c413badc067c *R/geom-density-line.R 199bd0f3c89c3f2c341bd1b4a133a4e4 *R/geoms-gradient.R b434afb84d7e8f1d28e85d002968bf1d *R/geoms.R 569e23723a6bd7217fc1c930f6569f0e *R/geomsv.R 73df4416a9ee3b2ea0e2d7afc36f597f *R/ggridges.R b511d763d003f5232b2876d061572238 *R/position.R 6a46c69a8130645008e2c5ba0dd58081 *R/scale-cyclical.R 23f6fdcdeb6cd71f86d016f6cf2bc4ec *R/scale-point.R a246e8f301a8cbdad6c783149d894e22 *R/scale-vline.R fba0b83df0ed3dd939eb2215365e07ff *R/stats.R 40866416a0d4bae03060dbcc5fbffe0a *R/theme.R 268953790e27c508186e4bf0f355f389 *R/utils.R 4e7b6b046e9c32177db46516a4b15121 *R/utils_ggplot2.R 5a4b953d297d5ee18803ae1dfc656972 *README.md a6827d97b9a55b34332eaff78a6477e5 *TODO c1ea149896fbdd73f484ec2d7a2b862e *build/vignette.rds 129d760577f3098da30b7d2e53ef7b71 *data/Aus_athletes.rda ae6a032f21b19edd2822adc7354cab7b *data/Catalan_elections.rda e2635efc0fc194d818e9d815160d91b6 *data/lincoln_weather.rda adbde66c10aebc49781bb84b1156e24c *inst/doc/gallery.R 0494549169fbdf44946a74f0aad6a17e *inst/doc/gallery.Rmd 728af2a079bc19eeeb6f4b5cb0b3f14b *inst/doc/gallery.html c7b79b51ee2e36ec0767ed07a8485734 *inst/doc/introduction.R c6dd17bd1b89943776c59c9c85bec8f2 *inst/doc/introduction.Rmd 8cd85d3b02712cdf5f1ce5d5822e55f1 *inst/doc/introduction.html 1a6acb2292c60997ad040d63221280db *man/Aus_athletes.Rd 79cf1d268388200a3ea09d6529d1719a *man/Catalan_elections.Rd fba66ec6df9d61967a1e27b72ac65d7d *man/figures/README-diamonds-1.png 67d3ab75b56e6f72d1f5034ebb8b313f *man/geom_density_line.Rd a3a5bf994f8290a2a6896c594af40ea6 *man/geom_density_ridges.Rd 0acc643b63448e039051e21fb88704b8 *man/geom_ridgeline.Rd 6954115536eee72713bed6b2824cdccf *man/geom_ridgeline_gradient.Rd bd2d704a3573eca02e86a2a5e18229a6 *man/geom_vridgeline.Rd 9c899a9f095bf0103e51e1ff4eee5cb5 *man/ggridges.Rd e22697fb5e4968c804024fc5c1a3072b *man/lincoln_weather.Rd 0121458ad7d42d53722086d22cec47c3 *man/position_points_jitter.Rd e85113eabea86cbbf705d80954f85c88 *man/position_points_sina.Rd 705465836f471ddbb6d4ec6ed81ff619 *man/position_raincloud.Rd 88dfd6d37c3da47c0a9120727d71dfb6 *man/reduce.Rd c450f250ffd34ed5439eeb2ee308cabb *man/scale_cyclical.Rd 0433828694f2e29e7fb0f3d00ceb22a7 *man/scale_point.Rd 696747bb88d4157ba77420fc294dd5a6 *man/scale_vline.Rd abc646a8b9a8a652eb6e6a5abe2d29a6 *man/stat_binline.Rd 12bb4a2ea3190a69ed0078d6dda88cbf *man/stat_density_ridges.Rd 500302139d2b9719629e7d5a88781f50 *man/theme_ridges.Rd b0ab17eb094c0a55dc40999f1f0c666a *tests/figs/deps.txt b3c2466e8455bf6950a804551004e250 *tests/figs/geom-density-ridges/geom-density-ridges-basic.svg fcfd5f79cf13263c97589d6aca9bca13 *tests/figs/geom-density-ridges/geom-density-ridges-no-trailing-lines.svg 71ce481733f4cbeb679f89adffeffc53 *tests/figs/geom-density-ridges/geom-density-ridges-scale-3.svg 0bc4803c4c9628caf3d843d8614f9812 *tests/figs/geom-density-ridges/geom-density-ridges2-solid-polygons.svg 66738d65a9dda8d3cd12a9126af4940e *tests/figs/geom-gradient/geom-density-ridges-gradient-continuous-fill.svg f0b7d5707ba04d6e3ce8cdbd08ca69f6 *tests/figs/geom-gradient/geom-density-ridges-gradient-ecdf-fill.svg 5f72a6b2ab83cc1a778ac0e84019081e *tests/figs/geom-gradient/geom-density-ridges-gradient-jittered-points-can-be-turned-on.svg b54643adbc609a0a03d01977c59ed48b *tests/figs/geom-gradient/geom-density-ridges-gradient-probability-tails.svg 2cace57a01617baa9e22cee44354379d *tests/figs/geom-gradient/geom-density-ridges-gradient-quantile-lines-match-shading.svg b7e82447043e16329aa2aff3849e59a8 *tests/figs/geom-gradient/geom-density-ridges-gradient-quintiles.svg 358fa65d0e727524f187e6f182321555 *tests/figs/geom-gradient/geom-ridgeline-gradient-basic-fill-pattern.svg 90beb311a5740e8a6398e246aede401f *tests/figs/geom-vridgeline/geom-vridgeline-basic-use.svg c8e7d77da0d8407bde8e9cb89c515fed *tests/figs/geom-vridgeline/geom-vridgeline-using-stat-ydensity.svg 92edf1274914cd6a149299c7b48dfbcf *tests/figs/scale-cyclical/scale-fill-cyclical-red-green-blue-dots-no-legend.svg 501c80ce8e47ea60dc95f344e6b63183 *tests/figs/scale-cyclical/scale-fill-cyclical-red-green-blue-dots-with-legend.svg fd3cf02dcb4af666b9b7feee811ea72b *tests/figs/theme-ridges/theme-ridges-centered-axis-labels.svg aa9fbc6a7b786e124279249a3527af75 *tests/figs/theme-ridges/theme-ridges-default.svg 1d7ae4c4687f5a87a80ee067023776bc *tests/figs/theme-ridges/theme-ridges-without-grid.svg 3f388ab80be34273aa399278dd3f7a30 *tests/testthat.R 106f8ec85a70d479077525640d2d8f63 *tests/testthat/Rplots.pdf d7b68db6e494aae9ce1fa0d0922141f7 *tests/testthat/test_geom_density_ridges.R 954f061d72b53503f8e39b9ea683c703 *tests/testthat/test_geom_gradient.R dd340d1ac24e53def808b993ef52a44b *tests/testthat/test_geom_vridgeline.R f1bc43bc9c53d9d75656d26fceef20bd *tests/testthat/test_scale_cyclical.R c43d6abcb71872b2a2743cd886f6561a *tests/testthat/test_stat_binline.R 9b0e54d9ac3c769afead970a06ec5ef4 *tests/testthat/test_stat_density_ridges.R c4333a014490cfbb4a4f1b438fdbcc2b *tests/testthat/test_theme_ridges.R 9a93a481b7411f8a456c009f4a7f1a79 *tests/testthat/test_utils.R 0494549169fbdf44946a74f0aad6a17e *vignettes/gallery.Rmd c6dd17bd1b89943776c59c9c85bec8f2 *vignettes/introduction.Rmd ggridges/inst/0000755000176200001440000000000013606456142013031 5ustar liggesusersggridges/inst/doc/0000755000176200001440000000000013606456142013576 5ustar liggesusersggridges/inst/doc/introduction.Rmd0000644000176200001440000005004013606436215016761 0ustar liggesusers--- title: "Introduction to ggridges" author: "Claus O. Wilke" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: fig_width: 6 fig_height: 4 vignette: > %\VignetteIndexEntry{Introduction to ggridges} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- Ridgeline plots are partially overlapping line plots that create the impression of a mountain range. They can be quite useful for visualizing changes in distributions over time or space. ## Geoms The **ggridges** package provides two main geoms, `geom_ridgeline` and `geom_density_ridges`. The former takes height values directly to draw ridgelines, and the latter first estimates data densities and then draws those using ridgelines. ### Ridgelines The geom `geom_ridgeline` can be used to draw lines with a filled area underneath. ```{r warning = FALSE, message = FALSE} library(ggplot2) library(ggridges) data <- data.frame(x = 1:5, y = rep(1, 5), height = c(0, 1, 3, 4, 2)) ggplot(data, aes(x, y, height = height)) + geom_ridgeline() ``` Negative heights are allowed, but are cut off unless the `min_height` parameter is set negative as well. ```{r message = FALSE, fig.width=9, fig.height=3} library(patchwork) # for side-by-side plotting data <- data.frame(x = 1:5, y = rep(1, 5), height = c(0, 1, -1, 3, 2)) plot_base <- ggplot(data, aes(x, y, height = height)) plot_base + geom_ridgeline() | plot_base + geom_ridgeline(min_height = -2) ``` Multiple ridgelines can be drawn at the same time. They will be ordered such that the ones drawn higher up are in the background. When drawing multiple ridgelines at once, the `group` aesthetic must be specified so that the geom knows which parts of the data belong to which ridgeline. ```{r message = FALSE} d <- data.frame( x = rep(1:5, 3), y = c(rep(0, 5), rep(1, 5), rep(2, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1) ) ggplot(d, aes(x, y, height = height, group = y)) + geom_ridgeline(fill = "lightblue") ``` It is also possible to draw ridgelines with `geom_density_ridges` if we set `stat = "identity"`. In this case, the heights are automatically scaled such that the highest ridgeline just touches the one above at `scale = 1`. ```{r message = FALSE} ggplot(d, aes(x, y, height = height, group = y)) + geom_density_ridges(stat = "identity", scale = 1) ``` ### Density ridgeline plots The geom `geom_density_ridges` calculates density estimates from the provided data and then plots those, using the ridgeline visualization. The `height` aesthetic does not need to be specified in this case. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() ``` There is also `geom_density_ridges2`, which is identical to `geom_density_ridges` except it uses closed polygons instead of ridgelines for drawing. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges2() ``` The grouping aesthetic does not need to be provided if a categorical variable is mapped onto the y axis, but it does need to be provided if the variable is numerical. ```{r message=FALSE} # modified dataset that represents species as a number iris_num <- transform(iris, Species_num = as.numeric(Species)) # does not work, causes error # ggplot(iris_num, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() # works ggplot(iris_num, aes(x = Sepal.Length, y = Species_num, group = Species_num)) + geom_density_ridges() ``` Trailing tails can be cut off using the `rel_min_height` aesthetic. This aesthetic sets a percent cutoff relative to the highest point of any of the density curves. A value of 0.01 usually works well, but you may have to modify this parameter for different datasets. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(rel_min_height = 0.01) ``` The extent to which the different densities overlap can be controlled with the `scale` parameter. A setting of `scale=1` means the tallest density curve just touches the baseline of the next higher one. Smaller values create a separation between the curves, and larger values create more overlap. ```{r message=FALSE} # scale = 0.9, not quite touching ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 0.9) # scale = 1, exactly touching ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 1) # scale = 5, substantial overlap ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 5) ``` The scaling is calculated separately per panel, so if we facet-wrap by species each density curve exactly touches the next higher baseline. (This can be disabled by setting `panel_scaling = FALSE`.) ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 1) + facet_wrap(~Species) ``` ### Varying fill colors along the x axis Sometimes we would like to have the area under a ridgeline not filled with a single solid color but rather with colors that vary in some form along the x axis. This effect can be achieved with the geoms `geom_ridgeline_gradient` and `geom_density_ridges_gradient`. Both geoms work just like `geom_ridgeline` and `geom_density_ridges`, except that they allow for varying fill colors. **However,** they do not allow for alpha transparency in the fill. For technical reasons, we can have changing fill colors or transparency but not both. Here is a simple example of changing fill colors with `geom_ridgeline_gradient`: ```{r message = FALSE} d <- data.frame( x = rep(1:5, 3) + c(rep(0, 5), rep(0.3, 5), rep(0.6, 5)), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) ggplot(d, aes(x, y, height = height, group = y, fill = factor(x+y))) + geom_ridgeline_gradient() + scale_fill_viridis_d(direction = -1, guide = "none") ``` And here is an example using `geom_density_ridges_gradient`. Note that we need to map the calculated x value (`stat(x)`) onto the fill aesthetic, not the original temperature variable. This is the case because `geom_density_ridges_gradient` calls `stat_density_ridges` (described in the next section) which calculates new x values as part of its density calculation. ```{r message = FALSE} ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = Month, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + labs(title = 'Temperatures in Lincoln NE in 2016') ``` ## Stats The ggridges package provides a stat `stat_density_ridges` that replaces `stat_density` in the context of ridgeline plots. In addition to setting up the proper `height` for `geom_density_ridges`, this stat has a number of additional features that may be useful. ### Quantile lines and coloring by quantiles or probabilities By setting the option `quantile_lines = TRUE`, we can make `stat_density_ridges` calculate the position of lines indicating quantiles. By default, three lines are drawn, corresponding to the first, second, and third quartile: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE) ``` We can change the number of quantiles by specifying it via the `quantiles` option. Note that `quantiles = 2` implies one line (the median) at the boundary between the two quantiles. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE, quantiles = 2) ``` We can also specify quantiles by cut points rather than number. E.g., we can indicate the 2.5% and 97.5% tails. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE, quantiles = c(0.025, 0.975), alpha = 0.7) ``` Using the geom `geom_density_ridges_gradient` we can also color by quantile, via the calculated `stat(quantile)` aesthetic. Note that this aesthetic is only calculated if `calc_ecdf = TRUE`. ```{r message = FALSE} ggplot(iris, aes(x=Sepal.Length, y=Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = 4, quantile_lines = TRUE ) + scale_fill_viridis_d(name = "Quartiles") ``` We can use the same approach to highlight the tails of the distributions. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = c(0.025, 0.975) ) + scale_fill_manual( name = "Probability", values = c("#FF0000A0", "#A0A0A0A0", "#0000FFA0"), labels = c("(0, 0.025]", "(0.025, 0.975]", "(0.975, 1]") ) ``` Finally, when `calc_ecdf = TRUE`, we also have access to a calculated aesthetic `stat(ecdf)`, which represents the empirical cumulative density function for the distribution. This allows us to map the probabilities directly onto color. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = 0.5 - abs(0.5 - stat(ecdf)))) + stat_density_ridges(geom = "density_ridges_gradient", calc_ecdf = TRUE) + scale_fill_viridis_c(name = "Tail probability", direction = -1) ``` ### Jittering points The stat `stat_density_ridges` also provides the option to visualize the original data points from which the distributions are generated. This can be done by setting `jittered_points = TRUE`, either in `stat_density_ridges` or in `geom_density_ridges`: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE) ``` Where the points are shown can be controlled with position options, e.g. "raincloud" for the raincloud effect: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, position = "raincloud", alpha = 0.7, scale = 0.9 ) ``` We can also simulate a rug: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, position = position_points_jitter(width = 0.05, height = 0), point_shape = '|', point_size = 3, point_alpha = 1, alpha = 0.7, ) ``` Note that we are using `position_points_jitter()` here, not `position_jitter()`. We do this because `position_points_jitter()` knows to jitter only the points in a ridgeline plot, without touching the density lines. Styling the jittered points is a bit tricky but is possible with special scales provided by ggridges. First, there is `scale_discrete_manual()` which can be used to make arbitrary discrete scales for arbitrary aesthetics. We use it in the next example to style the point shapes. Second, there are various point aesthetic scales, such as `scale_point_color_hue()`. See the reference documentation for these scales for more details. ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = Species)) + geom_density_ridges( aes(point_color = Species, point_fill = Species, point_shape = Species), alpha = .2, point_alpha = 1, jittered_points = TRUE ) + scale_point_color_hue(l = 40) + scale_discrete_manual(aesthetics = "point_shape", values = c(21, 22, 23)) ``` All common aesthetics for points can be applied to the jittered points. However, the aesthetic names start with `point_`. In the next example, we have mapped an additional variable onto the size of the points. ```{r message = FALSE, fig.width = 6, fig.height = 6} ggplot(iris, aes(x = Sepal.Length, y = Species, fill = Species)) + geom_density_ridges( aes(point_shape = Species, point_fill = Species, point_size = Petal.Length), alpha = .2, point_alpha = 1, jittered_points = TRUE ) + scale_point_color_hue(l = 40) + scale_point_size_continuous(range = c(0.5, 4)) + scale_discrete_manual(aesthetics = "point_shape", values = c(21, 22, 23)) ``` Similarly, we have aesthetics for the vertical lines, named `vline_`. And the vertical lines can also be shifted so they are aligned with the jittered points. This allows us to generate figures such as the following: ```{r message = FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, quantile_lines = TRUE, scale = 0.9, alpha = 0.7, vline_size = 1, vline_color = "red", point_size = 0.4, point_alpha = 1, position = position_raincloud(adjust_vlines = TRUE) ) ``` ### Using alternative stats The stat `stat_density_ridges` may not always do exactly what you want it to do. If this is the case, you can use other stats that may be better for your respective application. First, `stat_density_ridges` estimates the data range and bandwidth for the density estimation from the entire data at once, rather than from each individual group of data. This choice makes ridgeline plots look more uniform, but the density estimates can in some cases look quite different from what you would get from `geom_density` or `stat_density`. This problem can be remedied by using `stat_density` with `geom_density_ridges`. This works just fine, we just need to make sure that we map the calculated density onto the `height` aesthetic. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, height = stat(density))) + geom_density_ridges(stat = "density") ``` Second, there may be scenarios in which you don't want `geom_density_ridges` to do any density estimation, for example because you have done so already yourself. In this case, you can use `stat_identity`. The benefit of using `geom_density_ridges` with `stat_identiy` over using `geom_ridgeline` directly is that `geom_density_ridges` provides automatic scaling. As an example, assume we have calculated density curves for the `Sepal.Length` column in the `iris` dataset: ```{r message=FALSE} library(dplyr) iris_densities <- iris %>% group_by(Species) %>% group_modify(~ ggplot2:::compute_density(.x$Sepal.Length, NULL)) %>% rename(Sepal.Length = x) iris_densities ``` We can plot these as follows: ```{r message=FALSE} ggplot(iris_densities, aes(x = Sepal.Length, y = Species, height = density)) + geom_density_ridges(stat = "identity") ``` Notice how this plot looks different from the one generated using `stat = "density"`, even though the density computation was exactly the same: (i) The density curves extend all the way to zero. (ii) There is no horizontal line extending all the way to the limits of the x axis. Finally, if you prefer histograms to density plots, you can also use `stat_binline`. Note that overlapping histograms can look strange, so this option is probably best used with a `scale` parameter < 1. The option `draw_baseline = FALSE` removes trailing lines to either side of the histogram. (For histograms, the `rel_min_height` parameter doesn't work very well.) ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species, height = stat(density))) + geom_density_ridges(stat = "binline", bins = 20, scale = 0.95, draw_baseline = FALSE) ``` ## Themes ridgeline plots tend to require some theme modifications to look good. Most importantly, the y-axis tick labels should be vertically aligned so that they are flush with the axis ticks rather than vertically centered. The ggridges package provides a theme `theme_ridges` that does this and a few other theme modifications. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + theme_ridges() ``` However, without any further modifications, there are still a few issues with this plot. First, the ridgeline for the virginica species is slightly cut off at the very top point. Second, the space between the x and y axis labels and the ridgelines is too large. We can fix both issues using the `expand` option for the axis scales. ```{r message=FALSE, warning=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = expand_scale(mult = c(0.01, .7))) + theme_ridges() ``` Instead of expanding the axis, you can also turn off clipping for the plot panel. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges() ``` By default, `theme_ridges` adds a grid, but the grid can be switched off when not needed. Also, axis titles can be centered. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE, center_axis_labels = TRUE) ``` If you prefer to use a different theme than `theme_ridges`, for example `theme_minimal`, it is still advisable to adjust the alignment of the axis tick labels and the axis scales. ```{r message=FALSE} ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_minimal(base_size = 14) + theme(axis.text.y = element_text(vjust = 0)) ``` ## Cyclical scales Many ridgeline plots improve in appearance if the filled areas are drawn with alternating colors. To simplify the generation of such plots, **ggridges** provides cyclical scales. These are scales that cycle through the aesthetic values provided. For example, if we use `scale_fill_cyclical(values = c("blue", "green"))` then `ggplot` will cycle through these two fill colors throughout the plot. ```{r message=FALSE} ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("blue", "green")) ``` By default, the cyclical scales will not draw a legend, because the legend will usually be confusing unless the labels are manually altered. Legends can be switched on via the `guide = "legend"` option, just like for all other scales. ```{r message=FALSE, fig.width = 5.5} ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("blue", "green"), guide = "legend") ``` Legends can be modified as usual. ```{r message=FALSE, fig.width = 5.5} ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical( name = "Fill colors", values = c("blue", "green"), labels = c("Fair" = "blue", "Good" = "green"), guide = "legend" ) ``` Cyclical scales are defined for all the common aesthetics one might want to change, such as color, size, alpha, and linetype, and the legends are combined when possible ```{r message=FALSE, fig.width = 6.5} ggplot(diamonds, aes(x = price, y = cut, fill = cut, color = cut)) + geom_density_ridges(scale = 4, size = 1) + scale_fill_cyclical( name = "Color scheme", values = c("blue", "green"), guide = "legend", labels = c("Fair" = "blue w/ black outline", "Good" = "green w/ yellow outline") ) + scale_color_cyclical( name = "Color scheme", values = c("black", "yellow"), guide = "legend", labels = c("Fair" = "blue w/ black outline", "Good" = "green w/ yellow outline") ) ``` Because these cyclical scales are generic **ggplot2** scales, they work with any geom that accepts the respective aesthetic. Thus, for example, we can make histograms with alternatingly colored bars. ```{r message=FALSE, fig.width = 6.5} ggplot(mpg, aes(x = class, fill = class, color = class)) + geom_bar(size = 1.5) + scale_fill_cyclical( name = "Color scheme", values = c("blue", "green"), guide = "legend", labels = c("blue w/ black outline", "green w/ yellow outline") ) + scale_color_cyclical( name = "Color scheme", values = c("black", "yellow"), guide = "legend", labels = c("blue w/ black outline", "green w/ yellow outline") ) ``` While the previous example won't win any design awards, more subtle effects can be helpful. ```{r message=FALSE, fig.width=5.5} mpg %>% group_by(class) %>% tally() %>% arrange(desc(n)) %>% mutate(class = factor(class, levels = class)) %>% ggplot(aes(x = class, y = n, fill = class)) + geom_col() + scale_fill_cyclical(values = c("#4040B0", "#9090F0")) + scale_y_continuous(expand = c(0, 0)) + theme_minimal() ``` ggridges/inst/doc/gallery.R0000644000176200001440000001255013606456126015365 0ustar liggesusers## ----echo=FALSE, include=FALSE------------------------------------------------ library(ggplot2) library(ggridges) ## ----message=FALSE, warning=FALSE, fig.width = 6, fig.height = 6-------------- library(ggplot2movies) ggplot(movies[movies$year>1912,], aes(x = length, y = year, group = year)) + geom_density_ridges(scale = 10, size = 0.25, rel_min_height = 0.03) + theme_ridges() + scale_x_continuous(limits = c(1, 200), expand = c(0, 0)) + scale_y_reverse( breaks = c(2000, 1980, 1960, 1940, 1920, 1900), expand = c(0, 0) ) + coord_cartesian(clip = "off") ## ----message=FALSE, warning=FALSE, fig.width = 6, fig.height = 8-------------- library(dplyr) library(forcats) Catalan_elections %>% mutate(YearFct = fct_rev(as.factor(Year))) %>% ggplot(aes(y = YearFct)) + geom_density_ridges( aes(x = Percent, fill = paste(YearFct, Option)), alpha = .8, color = "white", from = 0, to = 100 ) + labs( x = "Vote (%)", y = "Election Year", title = "Indy vs Unionist vote in Catalan elections", subtitle = "Analysis unit: municipalities (n = 949)", caption = "Marc Belzunces (@marcbeldata) | Source: Idescat" ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + scale_fill_cyclical( breaks = c("1980 Indy", "1980 Unionist"), labels = c(`1980 Indy` = "Indy", `1980 Unionist` = "Unionist"), values = c("#ff0000", "#0000ff", "#ff8080", "#8080ff"), name = "Option", guide = "legend" ) + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE) ## ----message=FALSE, warning=FALSE, fig.width = 7.5, fig.height = 5------------ ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = Month, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01, gradient_lwd = 1.) + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = expand_scale(mult = c(0.01, 0.25))) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + labs( title = 'Temperatures in Lincoln NE', subtitle = 'Mean temperatures (Fahrenheit) by month for 2016' ) + theme_ridges(font_size = 13, grid = TRUE) + theme(axis.title.y = element_blank()) ## ----message=FALSE, warning=FALSE, fig.width = 6, fig.height = 7-------------- # generate data set.seed(1234) pois_data <- data.frame(mean = rep(1:5, each = 10)) pois_data$group <- factor(pois_data$mean, levels = 5:1) pois_data$value <- rpois(nrow(pois_data), pois_data$mean) # make plot ggplot(pois_data, aes(x = value, y = group, group = group)) + geom_density_ridges2(aes(fill = group), stat = "binline", binwidth = 1, scale = 0.95) + geom_text( stat = "bin", aes( y = group + 0.95*stat(count/max(count)), label = ifelse(stat(count) > 0, stat(count), "") ), vjust = 1.4, size = 3, color = "white", binwidth = 1 ) + scale_x_continuous( breaks = c(0:12), limits = c(-.5, 13), expand = c(0, 0), name = "random value" ) + scale_y_discrete( expand = expand_scale(add = c(0, 1.)), name = "Poisson mean", labels = c("5.0", "4.0", "3.0", "2.0", "1.0") ) + scale_fill_cyclical(values = c("#0000B0", "#7070D0")) + labs( title = "Poisson random samples with different means", subtitle = "sample size n=10" ) + guides(y = "none") + theme_ridges(grid = FALSE) + theme( axis.title.x = element_text(hjust = 0.5), axis.title.y = element_text(hjust = 0.5) ) ## ----message=FALSE, fig.width = 7, fig.height = 5.5--------------------------- ggplot(Aus_athletes, aes(x = height, y = sport, color = sex, point_color = sex, fill = sex)) + geom_density_ridges( jittered_points = TRUE, scale = .95, rel_min_height = .01, point_shape = "|", point_size = 3, size = 0.25, position = position_points_jitter(height = 0) ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0), name = "height [cm]") + scale_fill_manual(values = c("#D55E0050", "#0072B250"), labels = c("female", "male")) + scale_color_manual(values = c("#D55E00", "#0072B2"), guide = "none") + scale_discrete_manual("point_color", values = c("#D55E00", "#0072B2"), guide = "none") + coord_cartesian(clip = "off") + guides(fill = guide_legend( override.aes = list( fill = c("#D55E00A0", "#0072B2A0"), color = NA, point_color = NA) ) ) + ggtitle("Height in Australian athletes") + theme_ridges(center = TRUE) ## ----message=FALSE, fig.width = 6, fig.height = 5----------------------------- set.seed(423) n1 <- 200 n2 <- 25 n3 <- 50 cols <- c('#F2DB2F', '#F7F19E', '#FBF186') cols_dark <- c("#D7C32F", "#DBD68C", "#DFD672") cheese <- data.frame( cheese = c(rep("buttercheese", n1), rep("Leerdammer", n2), rep("Swiss", n3)), x = c(runif(n1), runif(n2), runif(n3)), size = c( rnorm(n1, mean = .1, sd = .01), rnorm(n2, mean = 9, sd = 3), rnorm(n3, mean = 3, sd = 1) ) ) ggplot(cheese, aes(x = x, point_size = size, y = cheese, fill = cheese, color = cheese)) + geom_density_ridges( jittered_points = TRUE, point_color="white", scale = .8, rel_min_height = .2, size = 1.5 ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(limits = c(0, 1), expand = c(0, 0), name = "", breaks = NULL) + scale_point_size_continuous(range = c(0.01, 10), guide = "none") + scale_fill_manual(values = cols, guide = "none") + scale_color_manual(values = cols_dark, guide = "none") + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE, center = TRUE) ggridges/inst/doc/gallery.Rmd0000644000176200001440000001436213606437134015707 0ustar liggesusers--- title: "Gallery of ggridges examples" author: "Claus O. Wilke" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: fig_width: 4.5 fig_height: 3 vignette: > %\VignetteIndexEntry{Gallery of ggridges examples} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- ```{r echo=FALSE, include=FALSE} library(ggplot2) library(ggridges) ``` ## Evolution of movie lengths over time Data from the IMDB, as provided in the ggplot2movies package. ```{r message=FALSE, warning=FALSE, fig.width = 6, fig.height = 6} library(ggplot2movies) ggplot(movies[movies$year>1912,], aes(x = length, y = year, group = year)) + geom_density_ridges(scale = 10, size = 0.25, rel_min_height = 0.03) + theme_ridges() + scale_x_continuous(limits = c(1, 200), expand = c(0, 0)) + scale_y_reverse( breaks = c(2000, 1980, 1960, 1940, 1920, 1900), expand = c(0, 0) ) + coord_cartesian(clip = "off") ``` ## Results from Catalan regional elections, 1980-2015 Modified after a figure originally created by [Marc Belzunces.](https://twitter.com/marcbeldata/) ```{r message=FALSE, warning=FALSE, fig.width = 6, fig.height = 8} library(dplyr) library(forcats) Catalan_elections %>% mutate(YearFct = fct_rev(as.factor(Year))) %>% ggplot(aes(y = YearFct)) + geom_density_ridges( aes(x = Percent, fill = paste(YearFct, Option)), alpha = .8, color = "white", from = 0, to = 100 ) + labs( x = "Vote (%)", y = "Election Year", title = "Indy vs Unionist vote in Catalan elections", subtitle = "Analysis unit: municipalities (n = 949)", caption = "Marc Belzunces (@marcbeldata) | Source: Idescat" ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0)) + scale_fill_cyclical( breaks = c("1980 Indy", "1980 Unionist"), labels = c(`1980 Indy` = "Indy", `1980 Unionist` = "Unionist"), values = c("#ff0000", "#0000ff", "#ff8080", "#8080ff"), name = "Option", guide = "legend" ) + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE) ``` ## Temperatures in Lincoln, Nebraska Modified from a [blog post](http://austinwehrwein.com/data-visualization/it-brings-me-ggjoy/) by Austin Wehrwein. ```{r message=FALSE, warning=FALSE, fig.width = 7.5, fig.height = 5} ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = Month, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01, gradient_lwd = 1.) + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = expand_scale(mult = c(0.01, 0.25))) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + labs( title = 'Temperatures in Lincoln NE', subtitle = 'Mean temperatures (Fahrenheit) by month for 2016' ) + theme_ridges(font_size = 13, grid = TRUE) + theme(axis.title.y = element_blank()) ``` ## Visualization of Poisson random samples with different means Inspired by a [ggridges example](https://twitter.com/noamross/status/888405434381545472) by Noam Ross. ```{r message=FALSE, warning=FALSE, fig.width = 6, fig.height = 7} # generate data set.seed(1234) pois_data <- data.frame(mean = rep(1:5, each = 10)) pois_data$group <- factor(pois_data$mean, levels = 5:1) pois_data$value <- rpois(nrow(pois_data), pois_data$mean) # make plot ggplot(pois_data, aes(x = value, y = group, group = group)) + geom_density_ridges2(aes(fill = group), stat = "binline", binwidth = 1, scale = 0.95) + geom_text( stat = "bin", aes( y = group + 0.95*stat(count/max(count)), label = ifelse(stat(count) > 0, stat(count), "") ), vjust = 1.4, size = 3, color = "white", binwidth = 1 ) + scale_x_continuous( breaks = c(0:12), limits = c(-.5, 13), expand = c(0, 0), name = "random value" ) + scale_y_discrete( expand = expand_scale(add = c(0, 1.)), name = "Poisson mean", labels = c("5.0", "4.0", "3.0", "2.0", "1.0") ) + scale_fill_cyclical(values = c("#0000B0", "#7070D0")) + labs( title = "Poisson random samples with different means", subtitle = "sample size n=10" ) + guides(y = "none") + theme_ridges(grid = FALSE) + theme( axis.title.x = element_text(hjust = 0.5), axis.title.y = element_text(hjust = 0.5) ) ``` ## Height of Australian athletes ```{r message=FALSE, fig.width = 7, fig.height = 5.5} ggplot(Aus_athletes, aes(x = height, y = sport, color = sex, point_color = sex, fill = sex)) + geom_density_ridges( jittered_points = TRUE, scale = .95, rel_min_height = .01, point_shape = "|", point_size = 3, size = 0.25, position = position_points_jitter(height = 0) ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(expand = c(0, 0), name = "height [cm]") + scale_fill_manual(values = c("#D55E0050", "#0072B250"), labels = c("female", "male")) + scale_color_manual(values = c("#D55E00", "#0072B2"), guide = "none") + scale_discrete_manual("point_color", values = c("#D55E00", "#0072B2"), guide = "none") + coord_cartesian(clip = "off") + guides(fill = guide_legend( override.aes = list( fill = c("#D55E00A0", "#0072B2A0"), color = NA, point_color = NA) ) ) + ggtitle("Height in Australian athletes") + theme_ridges(center = TRUE) ``` ## A cheese plot Inspired by [this tweet](https://twitter.com/lenkiefer/status/932237461337575429) by Leonard Kiefer. ```{r message=FALSE, fig.width = 6, fig.height = 5} set.seed(423) n1 <- 200 n2 <- 25 n3 <- 50 cols <- c('#F2DB2F', '#F7F19E', '#FBF186') cols_dark <- c("#D7C32F", "#DBD68C", "#DFD672") cheese <- data.frame( cheese = c(rep("buttercheese", n1), rep("Leerdammer", n2), rep("Swiss", n3)), x = c(runif(n1), runif(n2), runif(n3)), size = c( rnorm(n1, mean = .1, sd = .01), rnorm(n2, mean = 9, sd = 3), rnorm(n3, mean = 3, sd = 1) ) ) ggplot(cheese, aes(x = x, point_size = size, y = cheese, fill = cheese, color = cheese)) + geom_density_ridges( jittered_points = TRUE, point_color="white", scale = .8, rel_min_height = .2, size = 1.5 ) + scale_y_discrete(expand = c(0, 0)) + scale_x_continuous(limits = c(0, 1), expand = c(0, 0), name = "", breaks = NULL) + scale_point_size_continuous(range = c(0.01, 10), guide = "none") + scale_fill_manual(values = cols, guide = "none") + scale_color_manual(values = cols_dark, guide = "none") + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE, center = TRUE) ``` ggridges/inst/doc/introduction.html0000644000176200001440000675425213606456142017232 0ustar liggesusers Introduction to ggridges

Introduction to ggridges

Claus O. Wilke

2020-01-11

Ridgeline plots are partially overlapping line plots that create the impression of a mountain range. They can be quite useful for visualizing changes in distributions over time or space.

Geoms

The ggridges package provides two main geoms, geom_ridgeline and geom_density_ridges. The former takes height values directly to draw ridgelines, and the latter first estimates data densities and then draws those using ridgelines.

Ridgelines

The geom geom_ridgeline can be used to draw lines with a filled area underneath.

Negative heights are allowed, but are cut off unless the min_height parameter is set negative as well.

Multiple ridgelines can be drawn at the same time. They will be ordered such that the ones drawn higher up are in the background. When drawing multiple ridgelines at once, the group aesthetic must be specified so that the geom knows which parts of the data belong to which ridgeline.

It is also possible to draw ridgelines with geom_density_ridges if we set stat = "identity". In this case, the heights are automatically scaled such that the highest ridgeline just touches the one above at scale = 1.

Density ridgeline plots

The geom geom_density_ridges calculates density estimates from the provided data and then plots those, using the ridgeline visualization. The height aesthetic does not need to be specified in this case.

There is also geom_density_ridges2, which is identical to geom_density_ridges except it uses closed polygons instead of ridgelines for drawing.

The grouping aesthetic does not need to be provided if a categorical variable is mapped onto the y axis, but it does need to be provided if the variable is numerical.

Trailing tails can be cut off using the rel_min_height aesthetic. This aesthetic sets a percent cutoff relative to the highest point of any of the density curves. A value of 0.01 usually works well, but you may have to modify this parameter for different datasets.

The extent to which the different densities overlap can be controlled with the scale parameter. A setting of scale=1 means the tallest density curve just touches the baseline of the next higher one. Smaller values create a separation between the curves, and larger values create more overlap.

The scaling is calculated separately per panel, so if we facet-wrap by species each density curve exactly touches the next higher baseline. (This can be disabled by setting panel_scaling = FALSE.)

Varying fill colors along the x axis

Sometimes we would like to have the area under a ridgeline not filled with a single solid color but rather with colors that vary in some form along the x axis. This effect can be achieved with the geoms geom_ridgeline_gradient and geom_density_ridges_gradient. Both geoms work just like geom_ridgeline and geom_density_ridges, except that they allow for varying fill colors. However, they do not allow for alpha transparency in the fill. For technical reasons, we can have changing fill colors or transparency but not both.

Here is a simple example of changing fill colors with geom_ridgeline_gradient:

And here is an example using geom_density_ridges_gradient. Note that we need to map the calculated x value (stat(x)) onto the fill aesthetic, not the original temperature variable. This is the case because geom_density_ridges_gradient calls stat_density_ridges (described in the next section) which calculates new x values as part of its density calculation.

Stats

The ggridges package provides a stat stat_density_ridges that replaces stat_density in the context of ridgeline plots. In addition to setting up the proper height for geom_density_ridges, this stat has a number of additional features that may be useful.

Quantile lines and coloring by quantiles or probabilities

By setting the option quantile_lines = TRUE, we can make stat_density_ridges calculate the position of lines indicating quantiles. By default, three lines are drawn, corresponding to the first, second, and third quartile:

We can change the number of quantiles by specifying it via the quantiles option. Note that quantiles = 2 implies one line (the median) at the boundary between the two quantiles.

We can also specify quantiles by cut points rather than number. E.g., we can indicate the 2.5% and 97.5% tails.

Using the geom geom_density_ridges_gradient we can also color by quantile, via the calculated stat(quantile) aesthetic. Note that this aesthetic is only calculated if calc_ecdf = TRUE.

We can use the same approach to highlight the tails of the distributions.

Finally, when calc_ecdf = TRUE, we also have access to a calculated aesthetic stat(ecdf), which represents the empirical cumulative density function for the distribution. This allows us to map the probabilities directly onto color.

Jittering points

The stat stat_density_ridges also provides the option to visualize the original data points from which the distributions are generated. This can be done by setting jittered_points = TRUE, either in stat_density_ridges or in geom_density_ridges:

Where the points are shown can be controlled with position options, e.g. “raincloud” for the raincloud effect:

We can also simulate a rug:

Note that we are using position_points_jitter() here, not position_jitter(). We do this because position_points_jitter() knows to jitter only the points in a ridgeline plot, without touching the density lines.

Styling the jittered points is a bit tricky but is possible with special scales provided by ggridges. First, there is scale_discrete_manual() which can be used to make arbitrary discrete scales for arbitrary aesthetics. We use it in the next example to style the point shapes. Second, there are various point aesthetic scales, such as scale_point_color_hue(). See the reference documentation for these scales for more details.

All common aesthetics for points can be applied to the jittered points. However, the aesthetic names start with point_. In the next example, we have mapped an additional variable onto the size of the points.

Similarly, we have aesthetics for the vertical lines, named vline_. And the vertical lines can also be shifted so they are aligned with the jittered points. This allows us to generate figures such as the following:

Using alternative stats

The stat stat_density_ridges may not always do exactly what you want it to do. If this is the case, you can use other stats that may be better for your respective application. First, stat_density_ridges estimates the data range and bandwidth for the density estimation from the entire data at once, rather than from each individual group of data. This choice makes ridgeline plots look more uniform, but the density estimates can in some cases look quite different from what you would get from geom_density or stat_density. This problem can be remedied by using stat_density with geom_density_ridges. This works just fine, we just need to make sure that we map the calculated density onto the height aesthetic.

Second, there may be scenarios in which you don’t want geom_density_ridges to do any density estimation, for example because you have done so already yourself. In this case, you can use stat_identity. The benefit of using geom_density_ridges with stat_identiy over using geom_ridgeline directly is that geom_density_ridges provides automatic scaling.

As an example, assume we have calculated density curves for the Sepal.Length column in the iris dataset:

## # A tibble: 1,536 x 7
## # Groups:   Species [3]
##    Species Sepal.Length  density   scaled ndensity  count     n
##    <fct>          <dbl>    <dbl>    <dbl>    <dbl>  <dbl> <int>
##  1 setosa          3.93 0.000869 0.000701 0.000701 0.0435    50
##  2 setosa          3.94 0.000973 0.000785 0.000785 0.0487    50
##  3 setosa          3.94 0.00109  0.000876 0.000876 0.0543    50
##  4 setosa          3.94 0.00121  0.000975 0.000975 0.0604    50
##  5 setosa          3.95 0.00135  0.00109  0.00109  0.0673    50
##  6 setosa          3.95 0.00150  0.00121  0.00121  0.0749    50
##  7 setosa          3.96 0.00166  0.00134  0.00134  0.0831    50
##  8 setosa          3.96 0.00184  0.00149  0.00149  0.0922    50
##  9 setosa          3.97 0.00205  0.00165  0.00165  0.102     50
## 10 setosa          3.97 0.00226  0.00183  0.00183  0.113     50
## # … with 1,526 more rows

We can plot these as follows:

Notice how this plot looks different from the one generated using stat = "density", even though the density computation was exactly the same: (i) The density curves extend all the way to zero. (ii) There is no horizontal line extending all the way to the limits of the x axis.

Finally, if you prefer histograms to density plots, you can also use stat_binline. Note that overlapping histograms can look strange, so this option is probably best used with a scale parameter < 1. The option draw_baseline = FALSE removes trailing lines to either side of the histogram. (For histograms, the rel_min_height parameter doesn’t work very well.)

Themes

ridgeline plots tend to require some theme modifications to look good. Most importantly, the y-axis tick labels should be vertically aligned so that they are flush with the axis ticks rather than vertically centered. The ggridges package provides a theme theme_ridges that does this and a few other theme modifications.

However, without any further modifications, there are still a few issues with this plot. First, the ridgeline for the virginica species is slightly cut off at the very top point. Second, the space between the x and y axis labels and the ridgelines is too large. We can fix both issues using the expand option for the axis scales.

Instead of expanding the axis, you can also turn off clipping for the plot panel.

By default, theme_ridges adds a grid, but the grid can be switched off when not needed. Also, axis titles can be centered.

If you prefer to use a different theme than theme_ridges, for example theme_minimal, it is still advisable to adjust the alignment of the axis tick labels and the axis scales.

Cyclical scales

Many ridgeline plots improve in appearance if the filled areas are drawn with alternating colors. To simplify the generation of such plots, ggridges provides cyclical scales. These are scales that cycle through the aesthetic values provided. For example, if we use scale_fill_cyclical(values = c("blue", "green")) then ggplot will cycle through these two fill colors throughout the plot.

By default, the cyclical scales will not draw a legend, because the legend will usually be confusing unless the labels are manually altered. Legends can be switched on via the guide = "legend" option, just like for all other scales.

Legends can be modified as usual.

Cyclical scales are defined for all the common aesthetics one might want to change, such as color, size, alpha, and linetype, and the legends are combined when possible

Because these cyclical scales are generic ggplot2 scales, they work with any geom that accepts the respective aesthetic. Thus, for example, we can make histograms with alternatingly colored bars.

While the previous example won’t win any design awards, more subtle effects can be helpful.

ggridges/inst/doc/gallery.html0000644000176200001440000254141113606456127016136 0ustar liggesusers Gallery of ggridges examples

Gallery of ggridges examples

Claus O. Wilke

2020-01-11

ggridges/inst/doc/introduction.R0000644000176200001440000002672313606456142016454 0ustar liggesusers## ----warning = FALSE, message = FALSE----------------------------------------- library(ggplot2) library(ggridges) data <- data.frame(x = 1:5, y = rep(1, 5), height = c(0, 1, 3, 4, 2)) ggplot(data, aes(x, y, height = height)) + geom_ridgeline() ## ----message = FALSE, fig.width=9, fig.height=3------------------------------- library(patchwork) # for side-by-side plotting data <- data.frame(x = 1:5, y = rep(1, 5), height = c(0, 1, -1, 3, 2)) plot_base <- ggplot(data, aes(x, y, height = height)) plot_base + geom_ridgeline() | plot_base + geom_ridgeline(min_height = -2) ## ----message = FALSE---------------------------------------------------------- d <- data.frame( x = rep(1:5, 3), y = c(rep(0, 5), rep(1, 5), rep(2, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1) ) ggplot(d, aes(x, y, height = height, group = y)) + geom_ridgeline(fill = "lightblue") ## ----message = FALSE---------------------------------------------------------- ggplot(d, aes(x, y, height = height, group = y)) + geom_density_ridges(stat = "identity", scale = 1) ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges2() ## ----message=FALSE------------------------------------------------------------ # modified dataset that represents species as a number iris_num <- transform(iris, Species_num = as.numeric(Species)) # does not work, causes error # ggplot(iris_num, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() # works ggplot(iris_num, aes(x = Sepal.Length, y = Species_num, group = Species_num)) + geom_density_ridges() ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(rel_min_height = 0.01) ## ----message=FALSE------------------------------------------------------------ # scale = 0.9, not quite touching ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 0.9) # scale = 1, exactly touching ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 1) # scale = 5, substantial overlap ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 5) ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(scale = 1) + facet_wrap(~Species) ## ----message = FALSE---------------------------------------------------------- d <- data.frame( x = rep(1:5, 3) + c(rep(0, 5), rep(0.3, 5), rep(0.6, 5)), y = c(rep(0, 5), rep(1, 5), rep(3, 5)), height = c(0, 1, 3, 4, 0, 1, 2, 3, 5, 4, 0, 5, 4, 4, 1)) ggplot(d, aes(x, y, height = height, group = y, fill = factor(x+y))) + geom_ridgeline_gradient() + scale_fill_viridis_d(direction = -1, guide = "none") ## ----message = FALSE---------------------------------------------------------- ggplot(lincoln_weather, aes(x = `Mean Temperature [F]`, y = Month, fill = stat(x))) + geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01) + scale_fill_viridis_c(name = "Temp. [F]", option = "C") + labs(title = 'Temperatures in Lincoln NE in 2016') ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE, quantiles = 2) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + stat_density_ridges(quantile_lines = TRUE, quantiles = c(0.025, 0.975), alpha = 0.7) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x=Sepal.Length, y=Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = 4, quantile_lines = TRUE ) + scale_fill_viridis_d(name = "Quartiles") ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = factor(stat(quantile)))) + stat_density_ridges( geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = c(0.025, 0.975) ) + scale_fill_manual( name = "Probability", values = c("#FF0000A0", "#A0A0A0A0", "#0000FFA0"), labels = c("(0, 0.025]", "(0.025, 0.975]", "(0.975, 1]") ) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = 0.5 - abs(0.5 - stat(ecdf)))) + stat_density_ridges(geom = "density_ridges_gradient", calc_ecdf = TRUE) + scale_fill_viridis_c(name = "Tail probability", direction = -1) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges(jittered_points = TRUE) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, position = "raincloud", alpha = 0.7, scale = 0.9 ) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, position = position_points_jitter(width = 0.05, height = 0), point_shape = '|', point_size = 3, point_alpha = 1, alpha = 0.7, ) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = Species)) + geom_density_ridges( aes(point_color = Species, point_fill = Species, point_shape = Species), alpha = .2, point_alpha = 1, jittered_points = TRUE ) + scale_point_color_hue(l = 40) + scale_discrete_manual(aesthetics = "point_shape", values = c(21, 22, 23)) ## ----message = FALSE, fig.width = 6, fig.height = 6--------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species, fill = Species)) + geom_density_ridges( aes(point_shape = Species, point_fill = Species, point_size = Petal.Length), alpha = .2, point_alpha = 1, jittered_points = TRUE ) + scale_point_color_hue(l = 40) + scale_point_size_continuous(range = c(0.5, 4)) + scale_discrete_manual(aesthetics = "point_shape", values = c(21, 22, 23)) ## ----message = FALSE---------------------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges( jittered_points = TRUE, quantile_lines = TRUE, scale = 0.9, alpha = 0.7, vline_size = 1, vline_color = "red", point_size = 0.4, point_alpha = 1, position = position_raincloud(adjust_vlines = TRUE) ) ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species, height = stat(density))) + geom_density_ridges(stat = "density") ## ----message=FALSE------------------------------------------------------------ library(dplyr) iris_densities <- iris %>% group_by(Species) %>% group_modify(~ ggplot2:::compute_density(.x$Sepal.Length, NULL)) %>% rename(Sepal.Length = x) iris_densities ## ----message=FALSE------------------------------------------------------------ ggplot(iris_densities, aes(x = Sepal.Length, y = Species, height = density)) + geom_density_ridges(stat = "identity") ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species, height = stat(density))) + geom_density_ridges(stat = "binline", bins = 20, scale = 0.95, draw_baseline = FALSE) ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + theme_ridges() ## ----message=FALSE, warning=FALSE--------------------------------------------- ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = expand_scale(mult = c(0.01, .7))) + theme_ridges() ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges() ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_ridges(grid = FALSE, center_axis_labels = TRUE) ## ----message=FALSE------------------------------------------------------------ ggplot(iris, aes(x = Sepal.Length, y = Species)) + geom_density_ridges() + scale_x_continuous(expand = c(0, 0)) + scale_y_discrete(expand = c(0, 0)) + coord_cartesian(clip = "off") + theme_minimal(base_size = 14) + theme(axis.text.y = element_text(vjust = 0)) ## ----message=FALSE------------------------------------------------------------ ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("blue", "green")) ## ----message=FALSE, fig.width = 5.5------------------------------------------- ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical(values = c("blue", "green"), guide = "legend") ## ----message=FALSE, fig.width = 5.5------------------------------------------- ggplot(diamonds, aes(x = price, y = cut, fill = cut)) + geom_density_ridges(scale = 4) + scale_fill_cyclical( name = "Fill colors", values = c("blue", "green"), labels = c("Fair" = "blue", "Good" = "green"), guide = "legend" ) ## ----message=FALSE, fig.width = 6.5------------------------------------------- ggplot(diamonds, aes(x = price, y = cut, fill = cut, color = cut)) + geom_density_ridges(scale = 4, size = 1) + scale_fill_cyclical( name = "Color scheme", values = c("blue", "green"), guide = "legend", labels = c("Fair" = "blue w/ black outline", "Good" = "green w/ yellow outline") ) + scale_color_cyclical( name = "Color scheme", values = c("black", "yellow"), guide = "legend", labels = c("Fair" = "blue w/ black outline", "Good" = "green w/ yellow outline") ) ## ----message=FALSE, fig.width = 6.5------------------------------------------- ggplot(mpg, aes(x = class, fill = class, color = class)) + geom_bar(size = 1.5) + scale_fill_cyclical( name = "Color scheme", values = c("blue", "green"), guide = "legend", labels = c("blue w/ black outline", "green w/ yellow outline") ) + scale_color_cyclical( name = "Color scheme", values = c("black", "yellow"), guide = "legend", labels = c("blue w/ black outline", "green w/ yellow outline") ) ## ----message=FALSE, fig.width=5.5--------------------------------------------- mpg %>% group_by(class) %>% tally() %>% arrange(desc(n)) %>% mutate(class = factor(class, levels = class)) %>% ggplot(aes(x = class, y = n, fill = class)) + geom_col() + scale_fill_cyclical(values = c("#4040B0", "#9090F0")) + scale_y_continuous(expand = c(0, 0)) + theme_minimal()