├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ └── test-coverage.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── LICENSE.note ├── NAMESPACE ├── NEWS.md ├── R ├── aaa.R ├── arc.R ├── arc_bar.R ├── autodensity.R ├── autohistogram.R ├── autopoint.R ├── bezier.R ├── bspline.R ├── bspline_closed.R ├── circle.R ├── concaveman.R ├── cpp11.R ├── diagonal.R ├── diagonal_wide.R ├── ellipse.R ├── errorbar.R ├── facet_grid_paginate.R ├── facet_matrix.R ├── facet_row.R ├── facet_stereo.R ├── facet_wrap_paginate.R ├── facet_zoom.R ├── ggforce-package.R ├── ggproto-classes.R ├── interpolate.R ├── labeller.R ├── link.R ├── mark_circle.R ├── mark_ellipse.R ├── mark_hull.R ├── mark_label.R ├── mark_rect.R ├── parallel_sets.R ├── position-jitternormal.R ├── position_auto.R ├── position_floatstack.R ├── regon.R ├── scale-depth.R ├── scale-unit.R ├── shape.R ├── sina.R ├── spiro.R ├── themes.R ├── trans.R ├── trans_linear.R ├── utilities.R ├── voronoi.R └── zzz.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── man ├── facet_grid_paginate.Rd ├── facet_matrix.Rd ├── facet_row.Rd ├── facet_stereo.Rd ├── facet_wrap_paginate.Rd ├── facet_zoom.Rd ├── figures │ ├── README-example-1.png │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ ├── logo.png │ └── logo.svg ├── gather_set_data.Rd ├── geom_arc.Rd ├── geom_arc_bar.Rd ├── geom_autohistogram.Rd ├── geom_autopoint.Rd ├── geom_bezier.Rd ├── geom_bspline.Rd ├── geom_bspline_closed.Rd ├── geom_circle.Rd ├── geom_delvor.Rd ├── geom_diagonal.Rd ├── geom_diagonal_wide.Rd ├── geom_ellipse.Rd ├── geom_link.Rd ├── geom_mark_circle.Rd ├── geom_mark_ellipse.Rd ├── geom_mark_hull.Rd ├── geom_mark_rect.Rd ├── geom_parallel_sets.Rd ├── geom_regon.Rd ├── geom_shape.Rd ├── geom_sina.Rd ├── geom_spiro.Rd ├── ggforce-extensions.Rd ├── ggforce-package.Rd ├── interpolateDataFrame.Rd ├── label_tex.Rd ├── linear_trans.Rd ├── n_pages.Rd ├── position_auto.Rd ├── position_jitternormal.Rd ├── power_trans.Rd ├── radial_trans.Rd ├── scale_depth.Rd ├── scale_unit.Rd ├── shapeGrob.Rd ├── stat_err.Rd ├── theme_no_axes.Rd └── trans_reverser.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── revdep ├── README.md ├── cran.md ├── failures.md └── problems.md └── src ├── .gitignore ├── bSpline.cpp ├── bezier.cpp ├── concaveman.cpp ├── concaveman.h ├── cpp11.cpp ├── deBoor.cpp ├── deBoor.h ├── ellipseEnclose.cpp ├── enclose.cpp ├── pointPath.cpp └── robust_predicate ├── basebase.hpp ├── expansion ├── dd_float.hpp ├── ia_float.hpp ├── mp_basic.hpp ├── mp_float.hpp └── mp_utils.hpp ├── geompred.hpp ├── mpfloats.hpp └── predicate ├── bisect_k.hpp ├── inball_k.hpp ├── orient_k.hpp └── predicate_k.hpp /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | # 4 | # NOTE: This workflow is overkill for most R packages and 5 | # check-standard.yaml is likely a better choice. 6 | # usethis::use_github_action("check-standard") will install it. 7 | on: 8 | push: 9 | branches: [main, master] 10 | pull_request: 11 | branches: [main, master] 12 | 13 | name: R-CMD-check 14 | 15 | jobs: 16 | R-CMD-check: 17 | runs-on: ${{ matrix.config.os }} 18 | 19 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | config: 25 | - {os: macos-latest, r: 'release'} 26 | 27 | - {os: windows-latest, r: 'release'} 28 | # Use 3.6 to trigger usage of RTools35 29 | - {os: windows-latest, r: '3.6'} 30 | # use 4.1 to check with rtools40's older compiler 31 | - {os: windows-latest, r: '4.1'} 32 | 33 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 34 | - {os: ubuntu-latest, r: 'release'} 35 | - {os: ubuntu-latest, r: 'oldrel-1'} 36 | - {os: ubuntu-latest, r: 'oldrel-2'} 37 | - {os: ubuntu-latest, r: 'oldrel-3'} 38 | - {os: ubuntu-latest, r: 'oldrel-4'} 39 | 40 | env: 41 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 42 | R_KEEP_PKG_SOURCE: yes 43 | 44 | steps: 45 | - uses: actions/checkout@v3 46 | 47 | - uses: r-lib/actions/setup-pandoc@v2 48 | 49 | - uses: r-lib/actions/setup-r@v2 50 | with: 51 | r-version: ${{ matrix.config.r }} 52 | http-user-agent: ${{ matrix.config.http-user-agent }} 53 | use-public-rspm: true 54 | 55 | - uses: r-lib/actions/setup-r-dependencies@v2 56 | with: 57 | extra-packages: any::rcmdcheck 58 | needs: check 59 | 60 | - uses: r-lib/actions/check-r-package@v2 61 | with: 62 | upload-snapshots: true 63 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | permissions: 23 | contents: write 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: r-lib/actions/setup-pandoc@v2 28 | 29 | - uses: r-lib/actions/setup-r@v2 30 | with: 31 | use-public-rspm: true 32 | 33 | - uses: r-lib/actions/setup-r-dependencies@v2 34 | with: 35 | extra-packages: any::pkgdown, local::. 36 | needs: website 37 | 38 | - name: Build site 39 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 40 | shell: Rscript {0} 41 | 42 | - name: Deploy to GitHub pages 🚀 43 | if: github.event_name != 'pull_request' 44 | uses: JamesIves/github-pages-deploy-action@v4.4.1 45 | with: 46 | clean: false 47 | branch: gh-pages 48 | folder: docs 49 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: Commands 8 | 9 | jobs: 10 | document: 11 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 12 | name: document 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - uses: r-lib/actions/pr-fetch@v2 20 | with: 21 | repo-token: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | - uses: r-lib/actions/setup-r@v2 24 | with: 25 | use-public-rspm: true 26 | 27 | - uses: r-lib/actions/setup-r-dependencies@v2 28 | with: 29 | extra-packages: any::roxygen2 30 | needs: pr-document 31 | 32 | - name: Document 33 | run: roxygen2::roxygenise() 34 | shell: Rscript {0} 35 | 36 | - name: commit 37 | run: | 38 | git config --local user.name "$GITHUB_ACTOR" 39 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 40 | git add man/\* NAMESPACE 41 | git commit -m 'Document' 42 | 43 | - uses: r-lib/actions/pr-push@v2 44 | with: 45 | repo-token: ${{ secrets.GITHUB_TOKEN }} 46 | 47 | style: 48 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 49 | name: style 50 | runs-on: ubuntu-latest 51 | env: 52 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 53 | steps: 54 | - uses: actions/checkout@v3 55 | 56 | - uses: r-lib/actions/pr-fetch@v2 57 | with: 58 | repo-token: ${{ secrets.GITHUB_TOKEN }} 59 | 60 | - uses: r-lib/actions/setup-r@v2 61 | 62 | - name: Install dependencies 63 | run: install.packages("styler") 64 | shell: Rscript {0} 65 | 66 | - name: Style 67 | run: styler::style_pkg() 68 | shell: Rscript {0} 69 | 70 | - name: commit 71 | run: | 72 | git config --local user.name "$GITHUB_ACTOR" 73 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 74 | git add \*.R 75 | git commit -m 'Style' 76 | 77 | - uses: r-lib/actions/pr-push@v2 78 | with: 79 | repo-token: ${{ secrets.GITHUB_TOKEN }} 80 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | extra-packages: any::covr 27 | needs: coverage 28 | 29 | - name: Test coverage 30 | run: | 31 | covr::codecov( 32 | quiet = FALSE, 33 | clean = FALSE, 34 | install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") 35 | ) 36 | shell: Rscript {0} 37 | 38 | - name: Show testthat output 39 | if: always() 40 | run: | 41 | ## -------------------------------------------------------------------- 42 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 43 | shell: bash 44 | 45 | - name: Upload test results 46 | if: failure() 47 | uses: actions/upload-artifact@v3 48 | with: 49 | name: coverage-test-failures 50 | path: ${{ runner.temp }}/package 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | docs/ 2 | .Rproj.user 3 | .Rhistory 4 | .RData 5 | .Rbuildignore 6 | *.Rproj 7 | src/*.o 8 | src/*.so 9 | src/*.dll 10 | inst/doc 11 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (https://www.contributor-covenant.org), version 1.0.0, available at 25 | https://contributor-covenant.org/version/1/0/0/. 26 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ggforce 2 | Type: Package 3 | Title: Accelerating 'ggplot2' 4 | Version: 0.5.0 5 | Authors@R: 6 | c(person(given = "Thomas Lin", 7 | family = "Pedersen", 8 | role = c("cre", "aut"), 9 | email = "thomasp85@gmail.com", 10 | comment = c(ORCID = "0000-0002-5147-4711")), 11 | person("RStudio", 12 | role = "cph")) 13 | Maintainer: Thomas Lin Pedersen 14 | Description: The aim of 'ggplot2' is to aid in visual data investigations. This 15 | focus has led to a lack of facilities for composing specialised plots. 16 | 'ggforce' aims to be a collection of mainly new stats and geoms that fills 17 | this gap. All additional functionality is aimed to come through the official 18 | extension system so using 'ggforce' should be a stable experience. 19 | URL: https://ggforce.data-imaginist.com, https://github.com/thomasp85/ggforce 20 | BugReports: https://github.com/thomasp85/ggforce/issues 21 | License: MIT + file LICENSE 22 | Encoding: UTF-8 23 | Depends: 24 | ggplot2 (>= 3.5.0), 25 | R (>= 3.3.0) 26 | Imports: 27 | grid, 28 | scales, 29 | MASS, 30 | tweenr (>= 0.1.5), 31 | gtable, 32 | rlang, 33 | polyclip, 34 | stats, 35 | grDevices, 36 | tidyselect, 37 | withr, 38 | utils, 39 | lifecycle, 40 | cli, 41 | vctrs, 42 | systemfonts 43 | RoxygenNote: 7.3.1 44 | LinkingTo: 45 | cpp11 46 | Suggests: 47 | sessioninfo, 48 | deldir, 49 | latex2exp, 50 | reshape2, 51 | units (>= 0.8.0), 52 | covr 53 | Collate: 54 | 'aaa.R' 55 | 'shape.R' 56 | 'arc_bar.R' 57 | 'arc.R' 58 | 'autodensity.R' 59 | 'autohistogram.R' 60 | 'autopoint.R' 61 | 'bezier.R' 62 | 'bspline.R' 63 | 'bspline_closed.R' 64 | 'circle.R' 65 | 'concaveman.R' 66 | 'cpp11.R' 67 | 'diagonal.R' 68 | 'diagonal_wide.R' 69 | 'ellipse.R' 70 | 'errorbar.R' 71 | 'facet_grid_paginate.R' 72 | 'facet_matrix.R' 73 | 'facet_row.R' 74 | 'facet_stereo.R' 75 | 'facet_wrap_paginate.R' 76 | 'facet_zoom.R' 77 | 'ggforce-package.R' 78 | 'ggproto-classes.R' 79 | 'interpolate.R' 80 | 'labeller.R' 81 | 'link.R' 82 | 'mark_circle.R' 83 | 'mark_ellipse.R' 84 | 'mark_hull.R' 85 | 'mark_label.R' 86 | 'mark_rect.R' 87 | 'parallel_sets.R' 88 | 'position-jitternormal.R' 89 | 'position_auto.R' 90 | 'position_floatstack.R' 91 | 'regon.R' 92 | 'scale-depth.R' 93 | 'scale-unit.R' 94 | 'sina.R' 95 | 'spiro.R' 96 | 'themes.R' 97 | 'trans.R' 98 | 'trans_linear.R' 99 | 'utilities.R' 100 | 'voronoi.R' 101 | 'zzz.R' 102 | Roxygen: list(markdown = TRUE) 103 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Thomas Lin Pedersen 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2019 Thomas Lin Pedersen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.note: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | The concaveman.h file is redistributed with the following license 3 | 4 | BSD 2-Clause License 5 | 6 | Copyright (c) 2019, sadaszewski 7 | All rights reserved. 8 | 9 | Redistribution and use in source and binary forms, with or without 10 | modification, are permitted provided that the following conditions are met: 11 | 12 | 1. Redistributions of source code must retain the above copyright notice, this 13 | list of conditions and the following disclaimer. 14 | 15 | 2. Redistributions in binary form must reproduce the above copyright notice, 16 | this list of conditions and the following disclaimer in the documentation 17 | and/or other materials provided with the distribution. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | -------------------------------------------------------------------------------- 31 | The robust-predicates code used in concaveman is redistributed with the 32 | following license 33 | 34 | `Robust-Predicate` is licensed under the following terms: 35 | 36 | This program may be freely redistributed under the condition that the copyright 37 | notices (including this entire header) are not removed, and no compensation is 38 | received through use of the software. Private, research, and institutional use 39 | is free. You may distribute modified versions of this code `UNDER THE CONDITION 40 | THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE SAME FILE REMAIN UNDER 41 | COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE MADE FREELY 42 | AVAILABLE WITHOUT CHARGE, AND CLEAR NOTICE IS GIVEN OF THE MODIFICATIONS`. 43 | Distribution of this code as part of a commercial system is permissible `ONLY BY 44 | DIRECT ARRANGEMENT WITH THE AUTHOR`. (If you are not directly supplying this 45 | code to a customer, and you are instead telling them how they can obtain it for 46 | free, then you are not required to make any arrangement with me.) 47 | 48 | `DISCLAIMER`: Neither I nor: Columbia University, the Massachusetts Institute of 49 | Technology, the University of Sydney, nor the National Aeronautics and Space 50 | Administration warrant this code in any way whatsoever. This code is provided 51 | "as-is" to be used at your own risk. 52 | 53 | -------------------------------------------------------------------------------- 54 | -------------------------------------------------------------------------------- /R/aaa.R: -------------------------------------------------------------------------------- 1 | utils::globalVariables(c( 2 | 'x', 'y' 3 | )) 4 | 5 | `%||%` <- function(x, y) { 6 | if (is.null(x)) y else x 7 | } 8 | 9 | is.waive <- function(x) inherits(x, 'waiver') 10 | 11 | `%|W|%` <- function(x, y) { 12 | if (is.waive(x)) y else x 13 | } 14 | 15 | expand_default <- function(scale, discrete = c(0, 0.6), 16 | continuous = c(0.05, 0)) { 17 | scale$expand %|W|% if (scale$is_discrete()) discrete else continuous 18 | } 19 | 20 | combine_aes <- function(aes1, aes2) { 21 | aes_all <- c(aes1[setdiff(names(aes1), names(aes2))], aes2) 22 | class(aes_all) <- class(aes1) 23 | aes_all 24 | } 25 | 26 | empty_data <- function(x) { 27 | length(x) == 0 || nrow(x) == 0 28 | } 29 | 30 | # This function is like base::make.unique, but it 31 | # maintains the ordering of the original names if the values 32 | # are sorted. 33 | make_unique <- function(x, sep = '.') { 34 | if (!anyDuplicated(x)) return(x) 35 | groups <- match(x, unique(x)) 36 | suffix <- unsplit(lapply(split(x, groups), seq_along), groups) 37 | max_chars <- nchar(max(suffix)) 38 | suffix_format <- paste0('%0', max_chars, 'd') 39 | paste0(x, sep, sprintf(suffix_format, suffix)) 40 | } 41 | -------------------------------------------------------------------------------- /R/autodensity.R: -------------------------------------------------------------------------------- 1 | #' @rdname geom_autohistogram 2 | #' @inheritParams ggplot2::geom_point 3 | #' @inheritParams ggplot2::geom_density 4 | #' @export 5 | geom_autodensity <- function(mapping = NULL, data = NULL, 6 | stat = "autodensity", position = "floatstack", 7 | ..., 8 | bw = "nrd0", 9 | adjust = 1, 10 | kernel = "gaussian", 11 | n = 512, 12 | trim = FALSE, 13 | na.rm = FALSE, 14 | show.legend = NA, 15 | inherit.aes = TRUE, 16 | outline.type = "upper") { 17 | extra_mapping <- aes(x = .panel_x, y = .panel_y) 18 | if (is.null(mapping$x)) mapping$x <- extra_mapping$x 19 | if (is.null(mapping$y)) mapping$y <- extra_mapping$y 20 | class(mapping) <- 'uneval' 21 | 22 | layer( 23 | data = data, 24 | mapping = mapping, 25 | stat = stat, 26 | geom = GeomAutoarea, 27 | position = position, 28 | show.legend = show.legend, 29 | inherit.aes = inherit.aes, 30 | params = list2( 31 | bw = bw, 32 | adjust = adjust, 33 | kernel = kernel, 34 | n = n, 35 | trim = trim, 36 | na.rm = na.rm, 37 | ..., 38 | outline.type = outline.type 39 | ) 40 | ) 41 | } 42 | #' @rdname ggforce-extensions 43 | #' @format NULL 44 | #' @usage NULL 45 | #' @export 46 | StatAutodensity <- ggproto('StatAutodensity', StatDensity, 47 | setup_params = function(data, params) { 48 | params$panel_range <- lapply(split(data$y, data$PANEL), function(y) { 49 | if (length(y) == 0) return() 50 | range(y, na.rm=TRUE) 51 | }) 52 | params$panel_count <- lapply(split(data$y, data$PANEL), function(y)length(y[is.finite(y)])) 53 | 54 | params 55 | }, 56 | compute_group = function(self, data, scales, bw = "nrd0", adjust = 1, kernel = "gaussian", 57 | n = 512, trim = FALSE, na.rm = FALSE, panel_range = list(), panel_count = list()) { 58 | if (scales$x$is_discrete()) { 59 | bins <- split(data, factor(data$x, levels = seq_len(scales$x$range_c$range[2]))) 60 | binned <- lapply(as.integer(names(bins)), function(x) { 61 | count <- nrow(bins[[x]]) 62 | pad <- if (count == 0) 0.5 else 0.3 63 | pad <- pad * c(-1, 1) 64 | data_frame0( 65 | x = x + pad, 66 | density = count / nrow(data) 67 | ) 68 | }) 69 | binned <- vec_rbind(!!!binned) 70 | binned$scaled <- binned$density / max(binned$density) 71 | binned$ndensity <- binned$density / max(binned$density) 72 | binned$count <- binned$density * nrow(data) 73 | binned$n <- nrow(data) 74 | } else { 75 | binned <- ggproto_parent(StatDensity, self)$compute_group( 76 | data, scales, bw = bw, adjust = adjust, kernel = kernel, 77 | n = n, trim = trim, na.rm = na.rm 78 | ) 79 | } 80 | panel_range <- panel_range[[data$PANEL[1]]] 81 | panel_count <- panel_count[[data$PANEL[1]]] 82 | ymin <- panel_range[1] 83 | binned$y <- ymin + binned$ndensity * (panel_range[2] - panel_range[1]) * nrow(data) / panel_count 84 | 85 | binned$ymin <- ymin 86 | binned$ymax <- binned$y 87 | binned 88 | }, 89 | 90 | default_aes = aes(weight = 1), 91 | required_aes = c("x", "y") 92 | ) 93 | #' @rdname ggforce-extensions 94 | #' @format NULL 95 | #' @usage NULL 96 | #' @export 97 | GeomAutoarea <- ggproto('GeomAutoarea', GeomArea, 98 | setup_data = function(data, params) { 99 | data[order(data$PANEL, data$group, data$x), ] 100 | }, 101 | draw_panel = function(self, data, panel_params, coord, na.rm = FALSE, ...) { 102 | y_range <- coord$range(panel_params)$y 103 | y_span <- y_range[2] - y_range[1] 104 | panel_min <- min(data$ymin) 105 | panel_span <- max(data$ymax) - panel_min 106 | data$ymin <- ((data$ymin - panel_min) / panel_span) * y_span * 0.9 + y_range[1] 107 | data$ymax <- ((data$ymax - panel_min) / panel_span) * y_span * 0.9 + y_range[1] 108 | ggproto_parent(GeomArea, self)$draw_panel( 109 | data = data, 110 | panel_params = panel_params, 111 | coord = coord, 112 | na.rm = na.rm, 113 | ... 114 | ) 115 | } 116 | ) 117 | -------------------------------------------------------------------------------- /R/autohistogram.R: -------------------------------------------------------------------------------- 1 | #' A distribution geoms that fills the panel and works with discrete and continuous data 2 | #' 3 | #' These versions of the histogram and density geoms have been designed 4 | #' specifically for diagonal plotting with [facet_matrix()]. They differ from 5 | #' [ggplot2::geom_histogram()] and [ggplot2::geom_density()] in that they 6 | #' defaults to mapping `x` and `y` to `.panel_x` and `.panel_y` respectively, 7 | #' they ignore the y scale of the panel and fills it out, and they work for both 8 | #' continuous and discrete x scales. 9 | #' 10 | #' @inheritParams ggplot2::geom_histogram 11 | #' 12 | #' @seealso [facet_matrix] for creating matrix grids 13 | #' 14 | #' @export 15 | #' 16 | #' @examples 17 | #' # A matrix plot with a mix of discrete and continuous variables 18 | #' p <- ggplot(mpg) + 19 | #' geom_autopoint() + 20 | #' facet_matrix(vars(drv:fl), layer.diag = 2, grid.y.diag = FALSE) 21 | #' p 22 | #' 23 | #' # Diagonal histograms 24 | #' p + geom_autohistogram() 25 | #' 26 | #' # Diagonal density distributions 27 | #' p + geom_autodensity() 28 | #' 29 | #' # You can use them like regular layers with groupings etc 30 | #' p + geom_autodensity(aes(colour = drv, fill = drv), 31 | #' alpha = 0.4) 32 | geom_autohistogram <- function(mapping = NULL, data = NULL, 33 | stat = "autobin", position = "floatstack", 34 | ..., 35 | bins = NULL, 36 | na.rm = FALSE, 37 | show.legend = NA, 38 | inherit.aes = TRUE) { 39 | extra_mapping <- aes(x = .panel_x, y = .panel_y) 40 | if (is.null(mapping$x)) mapping$x <- extra_mapping$x 41 | if (is.null(mapping$y)) mapping$y <- extra_mapping$y 42 | class(mapping) <- 'uneval' 43 | 44 | layer( 45 | data = data, 46 | mapping = mapping, 47 | stat = stat, 48 | geom = GeomAutorect, 49 | position = position, 50 | show.legend = show.legend, 51 | inherit.aes = inherit.aes, 52 | params = list2( 53 | bins = bins, 54 | na.rm = na.rm, 55 | ... 56 | ) 57 | ) 58 | } 59 | #' @rdname ggforce-extensions 60 | #' @format NULL 61 | #' @usage NULL 62 | #' @export 63 | StatAutobin <- ggproto('StatAutobin', StatBin, 64 | setup_params = function(data, params) { 65 | if (is.null(params$bins)) params$bins <- 30 66 | params$panel_range <- lapply(split(data$y, data$PANEL), function(y) { 67 | if (length(y) == 0) return() 68 | range(y, na.rm=TRUE) 69 | }) 70 | params$panel_count <- lapply(split(data$y, data$PANEL), function(y)length(y[is.finite(y)])) 71 | 72 | params 73 | }, 74 | compute_group = function(self, data, scales, binwidth = NULL, bins = NULL, 75 | center = NULL, boundary = NULL, 76 | closed = c("right", "left"), pad = FALSE, 77 | breaks = NULL, panel_range = list(), panel_count = list(), 78 | # The following arguments are not used, but must 79 | # be listed so parameters are computed correctly 80 | origin = NULL, right = NULL, drop = NULL, 81 | width = NULL) { 82 | if (scales$x$is_discrete()) { 83 | binned <- lapply(split(data, data$x), function(d) { 84 | data_frame0( 85 | count = nrow(d), 86 | x = d$x[1], 87 | xmin = d$x[1] - 0.5, 88 | xmax = d$x[1] + 0.5, 89 | width = 1 90 | ) 91 | }) 92 | binned <- vec_rbind(!!!binned) 93 | binned$density <- binned$count / sum(binned$count) 94 | binned$ncount <- binned$count / max(binned$count) 95 | binned$ndensity <- binned$density / max(binned$density) 96 | } else { 97 | binned <- ggproto_parent(StatBin, self)$compute_group( 98 | data, scales, binwidth = binwidth, bins = bins, center = center, 99 | boundary = boundary, closed = closed, pad = pad, breaks = breaks, 100 | origin = origin, right = right, drop = drop 101 | ) 102 | } 103 | 104 | panel_range <- panel_range[[data$PANEL[1]]] 105 | panel_count <- panel_count[[data$PANEL[1]]] 106 | binned$ymin <- panel_range[1] 107 | binned$ymax <- binned$ymin + binned$ncount * (panel_range[2] - panel_range[1]) * nrow(data) / panel_count 108 | binned$y <- (binned$ymin + binned$ymax) / 2 109 | binned 110 | }, 111 | 112 | default_aes = aes(weight = 1), 113 | required_aes = c("x", "y") 114 | ) 115 | #' @rdname ggforce-extensions 116 | #' @format NULL 117 | #' @usage NULL 118 | #' @export 119 | GeomAutorect <- ggproto('PositionAutorect', GeomRect, 120 | draw_panel = function(self, data, panel_params, coord, ...) { 121 | y_range <- coord$range(panel_params)$y 122 | y_span <- y_range[2] - y_range[1] 123 | panel_min <- min(data$ymin) 124 | panel_span <- max(data$ymax) - panel_min 125 | data$ymin <- ((data$ymin - panel_min) / panel_span) * y_span * 0.9 + y_range[1] 126 | data$ymax <- ((data$ymax - panel_min) / panel_span) * y_span * 0.9 + y_range[1] 127 | ggproto_parent(GeomRect, self)$draw_panel(data, panel_params, coord, ...) 128 | }, 129 | extra_params = c('na.rm', 'lineend', 'linejoin') 130 | ) 131 | -------------------------------------------------------------------------------- /R/autopoint.R: -------------------------------------------------------------------------------- 1 | #' A point geom specialised for scatterplot matrices 2 | #' 3 | #' This geom is a specialisation of [ggplot2::geom_point()] with two changes. It 4 | #' defaults to mapping `x` and `y` to `.panel_x` and `.panel_y` respectively, 5 | #' and it defaults to using [position_auto()] to jitter the points based on the 6 | #' combination of position scale types. 7 | #' 8 | #' @inheritParams ggplot2::geom_point 9 | #' 10 | #' @seealso [facet_matrix] for how to lay out scatterplot matrices and 11 | #' [position_auto] for information about the position adjustments 12 | #' 13 | #' @export 14 | #' 15 | #' @examples 16 | #' # Continuous vs continuous: No jitter 17 | #' ggplot(mpg) + geom_autopoint(aes(cty, hwy)) 18 | #' 19 | #' # Continuous vs discrete: sina jitter 20 | #' ggplot(mpg) + geom_autopoint(aes(cty, drv)) 21 | #' 22 | #' # Discrete vs discrete: disc-jitter 23 | #' ggplot(mpg) + geom_autopoint(aes(fl, drv)) 24 | #' 25 | #' # Used with facet_matrix (x and y are automatically mapped) 26 | #' ggplot(mpg) + 27 | #' geom_autopoint() + 28 | #' facet_matrix(vars(drv:fl)) 29 | #' 30 | geom_autopoint <- function(mapping = NULL, data = NULL, 31 | stat = "identity", position = "auto", 32 | ..., 33 | na.rm = FALSE, 34 | show.legend = NA, 35 | inherit.aes = TRUE) { 36 | extra_mapping <- aes(x = .panel_x, y = .panel_y) 37 | if (is.null(mapping$x)) mapping$x <- extra_mapping$x 38 | if (is.null(mapping$y)) mapping$y <- extra_mapping$y 39 | class(mapping) <- 'uneval' 40 | layer( 41 | data = data, 42 | mapping = mapping, 43 | stat = stat, 44 | geom = GeomPoint, 45 | position = position, 46 | show.legend = show.legend, 47 | inherit.aes = inherit.aes, 48 | params = list2( 49 | na.rm = na.rm, 50 | ... 51 | ) 52 | ) 53 | } 54 | -------------------------------------------------------------------------------- /R/bspline_closed.R: -------------------------------------------------------------------------------- 1 | #' Create closed b-spline shapes 2 | #' 3 | #' This geom creates closed b-spline curves and draws them as shapes. The 4 | #' closed b-spline is achieved by wrapping the control points rather than the 5 | #' knots. The *0 version uses the [grid::xsplineGrob()] function with 6 | #' `open = FALSE` and can thus not be manipulated as a shape geom in the same 7 | #' way as the base version (expand, contract, etc). 8 | #' 9 | #' @section Aesthetics: 10 | #' geom_bspline_closed understand the following aesthetics (required aesthetics 11 | #' are in bold): 12 | #' 13 | #' - **x** 14 | #' - **y** 15 | #' - color 16 | #' - fill 17 | #' - linewidth 18 | #' - linetype 19 | #' - alpha 20 | #' 21 | #' @section Computed variables: 22 | #' 23 | #' \describe{ 24 | #' \item{x, y}{The coordinates for the path describing the spline} 25 | #' \item{index}{The progression along the interpolation mapped between 0 and 1} 26 | #' } 27 | #' 28 | #' @inheritParams ggplot2::geom_polygon 29 | #' @inheritParams ggplot2::stat_identity 30 | #' 31 | #' @param n The number of points generated for each spline 32 | #' 33 | #' @author Thomas Lin Pedersen. The C++ code for De Boor's algorithm has been 34 | #' adapted from 35 | #' \href{https://chi3x10.wordpress.com/2009/10/18/de-boor-algorithm-in-c/}{Jason Yu-Tseh Chi implementation} 36 | #' 37 | #' @name geom_bspline_closed 38 | #' @rdname geom_bspline_closed 39 | #' 40 | #' @examples 41 | #' # Create 6 random control points 42 | #' controls <- data.frame( 43 | #' x = runif(6), 44 | #' y = runif(6) 45 | #' ) 46 | #' 47 | #' ggplot(controls, aes(x, y)) + 48 | #' geom_polygon(fill = NA, colour = 'grey') + 49 | #' geom_point(colour = 'red') + 50 | #' geom_bspline_closed(alpha = 0.5) 51 | #' 52 | #' # The 0 version approximates the correct shape 53 | #' ggplot(controls, aes(x, y)) + 54 | #' geom_polygon(fill = NA, colour = 'grey') + 55 | #' geom_point(colour = 'red') + 56 | #' geom_bspline_closed0(alpha = 0.5) 57 | #' 58 | #' # But only the standard version supports geom_shape operations 59 | #' # Be aware of self-intersections though 60 | #' ggplot(controls, aes(x, y)) + 61 | #' geom_polygon(fill = NA, colour = 'grey') + 62 | #' geom_point(colour = 'red') + 63 | #' geom_bspline_closed(alpha = 0.5, expand = unit(2, 'cm')) 64 | NULL 65 | 66 | #' @rdname geom_bspline_closed 67 | #' @export 68 | stat_bspline_closed <- function(mapping = NULL, data = NULL, geom = 'shape', 69 | position = 'identity', na.rm = FALSE, n = 100, 70 | show.legend = NA, inherit.aes = TRUE, ...) { 71 | layer( 72 | stat = StatBspline, data = data, mapping = mapping, geom = geom, 73 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 74 | params = list2(na.rm = na.rm, n = n, ...) 75 | ) 76 | } 77 | #' @rdname geom_bspline_closed 78 | #' @export 79 | geom_bspline_closed <- function(mapping = NULL, data = NULL, stat = 'bspline', 80 | position = 'identity', n = 100, na.rm = FALSE, 81 | show.legend = NA, inherit.aes = TRUE, ...) { 82 | layer( 83 | data = data, mapping = mapping, stat = stat, geom = GeomShape, 84 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 85 | params = list2(na.rm = na.rm, n = n, type = 'closed', ...) 86 | ) 87 | } 88 | #' @rdname ggforce-extensions 89 | #' @format NULL 90 | #' @usage NULL 91 | #' @importFrom grid xsplineGrob gpar 92 | #' @export 93 | GeomBsplineClosed0 <- ggproto('GeomBspline0', GeomPolygon, 94 | draw_panel = function(data, panel_scales, coord, na.rm = FALSE) { 95 | coords <- coord$transform(data, panel_scales) 96 | if (!is.integer(coords$group)) { 97 | coords$group <- match(coords$group, unique0(coords$group)) 98 | } 99 | startPoint <- match(unique0(coords$group), coords$group) 100 | xsplineGrob(coords$x, coords$y, 101 | id = coords$group, default.units = 'native', 102 | shape = 1, open = FALSE, 103 | gp = gpar( 104 | col = coords$colour[startPoint], 105 | fill = ggplot2::fill_alpha(coords$fill[startPoint], coords$alpha[startPoint]), 106 | lwd = (coords$linewidth[startPoint] %||% coords$size[startPoint]) * .pt, 107 | lty = coords$linetype[startPoint] 108 | ) 109 | ) 110 | } 111 | ) 112 | 113 | #' @rdname geom_bspline_closed 114 | #' @export 115 | geom_bspline_closed0 <- function(mapping = NULL, data = NULL, stat = 'identity', 116 | position = 'identity', na.rm = FALSE, 117 | show.legend = NA, inherit.aes = TRUE, ...) { 118 | layer( 119 | data = data, mapping = mapping, stat = stat, geom = GeomBsplineClosed0, 120 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 121 | params = list2(na.rm = na.rm, ...) 122 | ) 123 | } 124 | -------------------------------------------------------------------------------- /R/circle.R: -------------------------------------------------------------------------------- 1 | #' @include arc_bar.R 2 | #' @include shape.R 3 | NULL 4 | 5 | #' Circles based on center and radius 6 | #' 7 | #' This set of stats and geoms makes it possible to draw circles based on a 8 | #' center point and a radius. In contrast to using 9 | #' [ggplot2::geom_point()], the size of the circles are related to the 10 | #' coordinate system and not to a separate scale. These functions are intended 11 | #' for cartesian coordinate systems and will only produce a true circle if 12 | #' [ggplot2::coord_fixed()] is used. 13 | #' 14 | #' @note If the intend is to draw a bubble chart then use 15 | #' [ggplot2::geom_point()] and map a variable to the size scale 16 | #' 17 | #' @section Aesthetics: 18 | #' geom_circle understand the following aesthetics (required aesthetics are in 19 | #' bold): 20 | #' 21 | #' - **x0** 22 | #' - **y0** 23 | #' - **r** 24 | #' - color 25 | #' - fill 26 | #' - linewidth 27 | #' - linetype 28 | #' - alpha 29 | #' - lineend 30 | #' 31 | #' @section Computed variables: 32 | #' 33 | #' \describe{ 34 | #' \item{x, y}{The start coordinates for the segment} 35 | #' } 36 | #' 37 | #' @inheritParams ggplot2::geom_path 38 | #' @inheritParams ggplot2::stat_identity 39 | #' 40 | #' @param n The number of points on the generated path per full circle. 41 | #' 42 | #' @name geom_circle 43 | #' @rdname geom_circle 44 | #' @seealso [geom_arc_bar()] for drawing arcs with fill 45 | #' 46 | #' @examples 47 | #' # Lets make some data 48 | #' circles <- data.frame( 49 | #' x0 = rep(1:3, 3), 50 | #' y0 = rep(1:3, each = 3), 51 | #' r = seq(0.1, 1, length.out = 9) 52 | #' ) 53 | #' 54 | #' # Behold some circles 55 | #' ggplot() + 56 | #' geom_circle(aes(x0 = x0, y0 = y0, r = r, fill = r), data = circles) 57 | #' 58 | #' # Use coord_fixed to ensure true circularity 59 | #' ggplot() + 60 | #' geom_circle(aes(x0 = x0, y0 = y0, r = r, fill = r), data = circles) + 61 | #' coord_fixed() 62 | #' 63 | NULL 64 | 65 | #' @rdname ggforce-extensions 66 | #' @format NULL 67 | #' @usage NULL 68 | #' @importFrom grid arcCurvature 69 | #' @export 70 | StatCircle <- ggproto('StatCircle', Stat, 71 | compute_panel = function(data, scales, n = 360) { 72 | # Avoid some weird interaction if x and y are mapped at the global level 73 | data$x <- NULL 74 | data$y <- NULL 75 | data$start <- 0 76 | data$end <- 2 * pi 77 | arcPaths(data, n + 1) 78 | }, 79 | 80 | required_aes = c('x0', 'y0', 'r') 81 | ) 82 | #' @rdname geom_circle 83 | #' @export 84 | stat_circle <- function(mapping = NULL, data = NULL, geom = 'circle', 85 | position = 'identity', n = 360, na.rm = FALSE, 86 | show.legend = NA, inherit.aes = TRUE, ...) { 87 | layer( 88 | stat = StatCircle, data = data, mapping = mapping, geom = geom, 89 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 90 | params = list2(na.rm = na.rm, n = n, ...) 91 | ) 92 | } 93 | #' @rdname ggforce-extensions 94 | #' @format NULL 95 | #' @usage NULL 96 | #' @export 97 | GeomCircle <- ggproto('GeomCircle', GeomShape, 98 | default_aes = combine_aes(GeomShape$default_aes, aes(colour = 'black', fill = NA)) 99 | ) 100 | #' @rdname geom_circle 101 | #' @inheritParams geom_shape 102 | #' @export 103 | geom_circle <- function(mapping = NULL, data = NULL, stat = 'circle', 104 | position = 'identity', n = 360, expand = 0, radius = 0, 105 | na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, 106 | ...) { 107 | layer( 108 | data = data, mapping = mapping, stat = stat, geom = GeomCircle, 109 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 110 | params = list2(n = n, na.rm = na.rm, ...) 111 | ) 112 | } 113 | -------------------------------------------------------------------------------- /R/concaveman.R: -------------------------------------------------------------------------------- 1 | concaveman <- function(points, concavity, threshold) { 2 | if (nrow(points) < 4) return(unname(points)) 3 | hull <- as.integer(grDevices::chull(points)) - 1L 4 | concaveman_c(points, hull, concavity, threshold) 5 | } 6 | -------------------------------------------------------------------------------- /R/cpp11.R: -------------------------------------------------------------------------------- 1 | # Generated by cpp11: do not edit by hand 2 | 3 | splinePath <- function(x, y, degree, knots, detail, type) { 4 | .Call(`_ggforce_splinePath`, x, y, degree, knots, detail, type) 5 | } 6 | 7 | getSplines <- function(x, y, id, detail, type) { 8 | .Call(`_ggforce_getSplines`, x, y, id, detail, type) 9 | } 10 | 11 | bezierPath <- function(x, y, detail) { 12 | .Call(`_ggforce_bezierPath`, x, y, detail) 13 | } 14 | 15 | getBeziers <- function(x, y, id, detail) { 16 | .Call(`_ggforce_getBeziers`, x, y, id, detail) 17 | } 18 | 19 | concaveman_c <- function(p, h, concavity, threshold) { 20 | .Call(`_ggforce_concaveman_c`, p, h, concavity, threshold) 21 | } 22 | 23 | enclose_ellip_points <- function(x, y, id, tol) { 24 | .Call(`_ggforce_enclose_ellip_points`, x, y, id, tol) 25 | } 26 | 27 | enclose_points <- function(x, y, id) { 28 | .Call(`_ggforce_enclose_points`, x, y, id) 29 | } 30 | 31 | points_to_path <- function(pos, path, close) { 32 | .Call(`_ggforce_points_to_path`, pos, path, close) 33 | } 34 | -------------------------------------------------------------------------------- /R/diagonal_wide.R: -------------------------------------------------------------------------------- 1 | #' Draw an area defined by an upper and lower diagonal 2 | #' 3 | #' The `geom_diagonal_wide()` function draws a *thick* diagonal, that is, a 4 | #' polygon confined between a lower and upper [diagonal][geom_diagonal]. This 5 | #' geom is bidirectional and the direction can be controlled with the 6 | #' `orientation` argument. 7 | #' 8 | #' @section Aesthetics: 9 | #' geom_diagonal_wide understand the following aesthetics 10 | #' (required aesthetics are in bold): 11 | #' 12 | #' - **x** 13 | #' - **y** 14 | #' - **group** 15 | #' - color 16 | #' - linewidth 17 | #' - linetype 18 | #' - alpha 19 | #' - lineend 20 | #' 21 | #' @inheritParams geom_shape 22 | #' @inheritParams ggplot2::stat_identity 23 | #' @inheritParams ggplot2::geom_line 24 | #' 25 | #' @param n The number of points to create for each of the bounding diagonals 26 | #' 27 | #' @param strength The proportion to move the control point along the x-axis 28 | #' towards the other end of the bezier curve 29 | #' 30 | #' @inheritSection ggplot2::geom_line Orientation 31 | #' 32 | #' @name geom_diagonal_wide 33 | #' @rdname geom_diagonal_wide 34 | #' 35 | #' @examples 36 | #' data <- data.frame( 37 | #' x = c(1, 2, 2, 1, 2, 3, 3, 2), 38 | #' y = c(1, 2, 3, 2, 3, 1, 2, 5), 39 | #' group = c(1, 1, 1, 1, 2, 2, 2, 2) 40 | #' ) 41 | #' 42 | #' ggplot(data) + 43 | #' geom_diagonal_wide(aes(x, y, group = group)) 44 | #' 45 | #' # The strength control the steepness 46 | #' ggplot(data, aes(x, y, group = group)) + 47 | #' geom_diagonal_wide(strength = 0.75, alpha = 0.5, fill = 'red') + 48 | #' geom_diagonal_wide(strength = 0.25, alpha = 0.5, fill = 'blue') 49 | #' 50 | #' # The diagonal_wide geom uses geom_shape under the hood, so corner rounding 51 | #' # etc are all there 52 | #' ggplot(data) + 53 | #' geom_diagonal_wide(aes(x, y, group = group), radius = unit(5, 'mm')) 54 | #' 55 | NULL 56 | 57 | #' @rdname ggforce-extensions 58 | #' @format NULL 59 | #' @usage NULL 60 | #' @export 61 | StatDiagonalWide <- ggproto('StatDiagonalWide', Stat, 62 | setup_params = function(data, params) { 63 | params$flipped_aes <- has_flipped_aes(data, params, ambiguous = TRUE) 64 | params 65 | }, 66 | setup_data = function(data, params) { 67 | data$flipped_aes <- params$flipped_aes 68 | if (any(table(data$group) != 4)) { 69 | cli::cli_abort('Each group must consist of 4 points') 70 | } 71 | data 72 | }, 73 | compute_panel = function(data, scales, strength = 0.5, n = 100, flipped_aes = FALSE) { 74 | data <- flip_data(data, flipped_aes) 75 | data <- data[order(data$group, data$x, data$y), ] 76 | lower <- data[rep_len(c(TRUE, FALSE, TRUE, FALSE), nrow(data)), ] 77 | upper <- data[rep_len(c(FALSE, TRUE, FALSE, TRUE), nrow(data)), ] 78 | lower <- add_controls(lower, strength) 79 | upper <- add_controls(upper[rev(seq_len(nrow(upper))), ], strength) 80 | lower <- StatBezier$compute_panel(lower, scales, n) 81 | upper <- StatBezier$compute_panel(upper, scales, n) 82 | diagonals <- vec_rbind(lower, upper) 83 | diagonals$index <- NULL 84 | diagonals <- diagonals[order(diagonals$group), ] 85 | flip_data(diagonals, flipped_aes) 86 | }, 87 | required_aes = c('x', 'y', 'group'), 88 | extra_params = c('na.rm', 'n', 'strength', 'orientation') 89 | ) 90 | #' @rdname geom_diagonal_wide 91 | #' @export 92 | stat_diagonal_wide <- function(mapping = NULL, data = NULL, geom = 'shape', 93 | position = 'identity', n = 100, strength = 0.5, 94 | na.rm = FALSE, orientation = NA, show.legend = NA, 95 | inherit.aes = TRUE, ...) { 96 | layer( 97 | stat = StatDiagonalWide, data = data, mapping = mapping, geom = geom, 98 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 99 | params = list2(na.rm = na.rm, orientation = orientation, n = n, 100 | strength = strength, ...) 101 | ) 102 | } 103 | #' @rdname geom_diagonal_wide 104 | #' @export 105 | geom_diagonal_wide <- function(mapping = NULL, data = NULL, stat = 'diagonal_wide', 106 | position = 'identity', n = 100, na.rm = FALSE, 107 | orientation = NA, strength = 0.5, 108 | show.legend = NA, inherit.aes = TRUE, ...) { 109 | layer( 110 | data = data, mapping = mapping, stat = stat, geom = GeomShape, 111 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 112 | params = list2(na.rm = na.rm, orientation = orientation, n = n, 113 | strength = strength, ...) 114 | ) 115 | } 116 | -------------------------------------------------------------------------------- /R/ellipse.R: -------------------------------------------------------------------------------- 1 | #' Draw (super)ellipses based on the coordinate system scale 2 | #' 3 | #' This is a generalisation of [geom_circle()] that allows you to draw 4 | #' ellipses at a specified angle and center relative to the coordinate system. 5 | #' Apart from letting you draw regular ellipsis, the stat is using the 6 | #' generalised formula for superellipses which can be utilised by setting the 7 | #' `m1` and `m2` aesthetics. If you only set the m1 the m2 value will follow 8 | #' that to ensure a symmetric appearance. 9 | #' 10 | #' @section Aesthetics: 11 | #' geom_arc understand the following aesthetics (required aesthetics are in 12 | #' bold): 13 | #' 14 | #' - **x0** 15 | #' - **y0** 16 | #' - **a** 17 | #' - **b** 18 | #' - **angle** 19 | #' - m1 20 | #' - m2 21 | #' - color 22 | #' - fill 23 | #' - linewidth 24 | #' - linetype 25 | #' - alpha 26 | #' - lineend 27 | #' 28 | #' @section Computed variables: 29 | #' 30 | #' \describe{ 31 | #' \item{x, y}{The coordinates for the points along the ellipse} 32 | #' } 33 | #' 34 | #' @inheritParams ggplot2::geom_path 35 | #' @inheritParams ggplot2::stat_identity 36 | #' 37 | #' @param n The number of points to sample along the ellipse. 38 | #' 39 | #' @name geom_ellipse 40 | #' @rdname geom_ellipse 41 | #' 42 | #' @examples 43 | #' # Basic usage 44 | #' ggplot() + 45 | #' geom_ellipse(aes(x0 = 0, y0 = 0, a = 10, b = 3, angle = 0)) + 46 | #' coord_fixed() 47 | #' 48 | #' # Rotation 49 | #' # Note that it expects radians and rotates the ellipse counter-clockwise 50 | #' ggplot() + 51 | #' geom_ellipse(aes(x0 = 0, y0 = 0, a = 10, b = 3, angle = pi / 4)) + 52 | #' coord_fixed() 53 | #' 54 | #' # Draw a super ellipse 55 | #' ggplot() + 56 | #' geom_ellipse(aes(x0 = 0, y0 = 0, a = 6, b = 3, angle = -pi / 3, m1 = 3)) + 57 | #' coord_fixed() 58 | NULL 59 | 60 | #' @rdname ggforce-extensions 61 | #' @format NULL 62 | #' @usage NULL 63 | #' @export 64 | StatEllip <- ggproto('StatEllip', Stat, 65 | setup_data = function(data, params) { 66 | data$m1 <- if (is.null(data$m1)) 2 else data$m1 67 | data$m2 <- if (is.null(data$m2)) data$m1 else data$m2 68 | data 69 | }, 70 | compute_panel = function(self, data, scales, n = 360) { 71 | if (empty_data(data)) return(data) 72 | data$group <- make_unique(data$group) 73 | n_ellipses <- nrow(data) 74 | data <- data[rep(seq_len(n_ellipses), each = n), ] 75 | points <- rep(seq(0, 2 * pi, length.out = n + 1)[seq_len(n)], 76 | n_ellipses) 77 | cos_p <- cos(points) 78 | sin_p <- sin(points) 79 | x_tmp <- abs(cos_p)^(2 / data$m1) * data$a * sign(cos_p) 80 | y_tmp <- abs(sin_p)^(2 / data$m2) * data$b * sign(sin_p) 81 | data$x <- data$x0 + x_tmp * cos(data$angle) - y_tmp * sin(data$angle) 82 | data$y <- data$y0 + x_tmp * sin(data$angle) + y_tmp * cos(data$angle) 83 | data 84 | }, 85 | required_aes = c('x0', 'y0', 'a', 'b', 'angle'), 86 | default_aes = aes(m1 = NA, m2 = NA), 87 | extra_params = c('n', 'na.rm') 88 | ) 89 | #' @rdname geom_ellipse 90 | #' @export 91 | stat_ellip <- function(mapping = NULL, data = NULL, geom = 'circle', 92 | position = 'identity', n = 360, na.rm = FALSE, 93 | show.legend = NA, inherit.aes = TRUE, ...) { 94 | layer( 95 | stat = StatEllip, data = data, mapping = mapping, geom = geom, 96 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 97 | params = list2(na.rm = na.rm, n = n, ...) 98 | ) 99 | } 100 | 101 | #' @rdname geom_ellipse 102 | #' @export 103 | geom_ellipse <- function(mapping = NULL, data = NULL, stat = 'ellip', 104 | position = 'identity', n = 360, na.rm = FALSE, 105 | show.legend = NA, inherit.aes = TRUE, ...) { 106 | layer( 107 | data = data, mapping = mapping, stat = stat, geom = GeomCircle, 108 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 109 | params = list2(n = n, na.rm = na.rm, ...) 110 | ) 111 | } 112 | -------------------------------------------------------------------------------- /R/errorbar.R: -------------------------------------------------------------------------------- 1 | #' @rdname ggforce-extensions 2 | #' @format NULL 3 | #' @usage NULL 4 | #' @export 5 | StatErr <- ggproto( 6 | "StatErr", 7 | Stat, 8 | required_aes = c('xmin', 'x', 'xmax', 'ymin', 'y', 'ymax'), 9 | compute_group = function(data, scales) { 10 | data_frame0( 11 | x = c(data$xmin, data$x), 12 | xend = c(data$xmax, data$x), 13 | y = c(data$y, data$ymin), 14 | yend = c(data$y, data$ymax) 15 | )[c(matrix(seq_len(2 * nrow(data)), nrow = 2, byrow = TRUE)), ] 16 | } 17 | ) 18 | 19 | #' Intervals in vertical and horizontal directions 20 | #' 21 | #' `stat_err` draws intervals of points (`x`, `y`) in vertical (`ymin`, `ymax`) 22 | #' and horizontal (`xmin`, `xmax`) directions. 23 | #' 24 | #' @section Aesthetics: 25 | #' `stat_err()` understands the following aesthetics (required aesthetics are in 26 | #' bold): 27 | #' 28 | #' - **x** 29 | #' - **xmin** 30 | #' - **xmax** 31 | #' - **y** 32 | #' - **ymin** 33 | #' - **ymax** 34 | #' - alpha 35 | #' - color 36 | #' - group 37 | #' - linetype 38 | #' - linewidth 39 | #' 40 | #' @examples 41 | #' library(ggplot2) 42 | #' 43 | #' x <- 1:3 44 | #' xmin <- x - 2.5 45 | #' xmax <- x + 2.5 46 | #' d <- data.frame( 47 | #' x = x, y = x, xmin = xmin, ymin = xmin, xmax = xmax, ymax = xmax, 48 | #' color = as.factor(x) 49 | #' ) 50 | #' ggplot( 51 | #' d, 52 | #' aes(x = x, y = y, xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, color = color) 53 | #' ) + 54 | #' stat_err(size = 2) 55 | #' 56 | #' @inheritParams ggplot2::layer 57 | #' @inheritParams ggplot2::geom_errorbar 58 | #' @inheritParams ggplot2::stat_identity 59 | #' 60 | #' @importFrom ggplot2 layer 61 | #' 62 | #' @export 63 | stat_err <- function( 64 | mapping = NULL, data = NULL, geom = "segment", position = "identity", 65 | na.rm = FALSE, show.legend = NA, inherit.aes = TRUE, ... 66 | ) { 67 | layer( 68 | stat = StatErr, data = data, mapping = mapping, geom = geom, 69 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 70 | params = list2(na.rm = na.rm, ...) 71 | ) 72 | } 73 | -------------------------------------------------------------------------------- /R/facet_grid_paginate.R: -------------------------------------------------------------------------------- 1 | #' Split facet_grid over multiple plots 2 | #' 3 | #' This extension to [ggplot2::facet_grid()] will allow you to split 4 | #' a facetted plot over multiple pages. You define a number of rows and columns 5 | #' per page as well as the page number to plot, and the function will 6 | #' automatically only plot the correct panels. Usually this will be put in a 7 | #' loop to render all pages one by one. 8 | #' 9 | #' @inheritParams ggplot2::facet_grid 10 | #' @param ncol Number of columns per page 11 | #' @param nrow Number of rows per page 12 | #' @param page The page to draw 13 | #' @param byrow Should the pages be created row-wise or column wise 14 | #' 15 | #' @note If either `ncol` or `nrow` is `NULL` this function will 16 | #' fall back to the standard `facet_grid` functionality. 17 | #' 18 | #' @family ggforce facets 19 | #' @seealso [n_pages()] to compute the total number of pages in a paginated 20 | #' faceted plot 21 | #' 22 | #' @export 23 | #' 24 | #' @examples 25 | #' # Draw a small section of the grid 26 | #' ggplot(diamonds) + 27 | #' geom_point(aes(carat, price), alpha = 0.1) + 28 | #' facet_grid_paginate(color ~ cut:clarity, ncol = 3, nrow = 3, page = 4) 29 | facet_grid_paginate <- function(facets, margins = FALSE, scales = 'fixed', 30 | space = 'fixed', shrink = TRUE, 31 | labeller = 'label_value', as.table = TRUE, 32 | switch = NULL, drop = TRUE, ncol = NULL, 33 | nrow = NULL, page = 1, byrow = TRUE) { 34 | facet <- facet_grid(facets, 35 | margins = margins, scales = scales, 36 | space = space, shrink = shrink, labeller = labeller, 37 | as.table = as.table, switch = switch, drop = drop 38 | ) 39 | if (is.null(nrow) || is.null(ncol)) { 40 | facet 41 | } else { 42 | ggproto(NULL, FacetGridPaginate, 43 | shrink = shrink, 44 | params = c( 45 | facet$params, 46 | list(ncol = ncol, nrow = nrow, page = page, byrow = byrow) 47 | ) 48 | ) 49 | } 50 | } 51 | 52 | #' @rdname ggforce-extensions 53 | #' @format NULL 54 | #' @usage NULL 55 | #' @importFrom gtable gtable_add_rows gtable_add_cols 56 | #' @export 57 | FacetGridPaginate <- ggproto('FacetGridPaginate', FacetGrid, 58 | compute_layout = function(data, params) { 59 | layout <- FacetGrid$compute_layout(data, params) 60 | row_bin <- ceiling(layout$ROW / params$nrow) 61 | col_bin <- ceiling(layout$COL / params$ncol) 62 | bin_layout <- matrix(seq_len(max(row_bin) * max(col_bin)), 63 | nrow = max(row_bin), byrow = params$byrow 64 | ) 65 | layout$page <- bin_layout[(col_bin - 1) * nrow(bin_layout) + row_bin] 66 | layout 67 | }, 68 | draw_panels = function(panels, layout, x_scales, y_scales, ranges, coord, data, 69 | theme, params) { 70 | include <- which(layout$page == params$page) 71 | panels <- panels[include] 72 | ranges <- ranges[include] 73 | layout <- layout[include, , drop = FALSE] 74 | layout$ROW <- layout$ROW - min(layout$ROW) + 1 75 | layout$COL <- layout$COL - min(layout$COL) + 1 76 | layout$PANEL <- 1:dim(layout)[1] 77 | x_scale_ind <- unique0(layout$SCALE_X) 78 | x_scales <- x_scales[x_scale_ind] 79 | layout$SCALE_X <- match(layout$SCALE_X, x_scale_ind) 80 | y_scale_ind <- unique0(layout$SCALE_Y) 81 | y_scales <- y_scales[y_scale_ind] 82 | layout$SCALE_Y <- match(layout$SCALE_Y, y_scale_ind) 83 | table <- FacetGrid$draw_panels(panels, layout, x_scales, y_scales, ranges, 84 | coord, data, theme, params) 85 | if (max(layout$ROW) != params$nrow) { 86 | spacing <- theme$panel.spacing.y %||% theme$panel.spacing 87 | missing_rows <- params$nrow - max(layout$ROW) 88 | table <- gtable_add_rows(table, unit(missing_rows, 'null')) 89 | table <- gtable_add_rows(table, spacing * missing_rows) 90 | } 91 | if (max(layout$COL) != params$ncol) { 92 | spacing <- theme$panel.spacing.x %||% theme$panel.spacing 93 | missing_cols <- params$ncol - max(layout$COL) 94 | table <- gtable_add_cols(table, unit(missing_cols, 'null')) 95 | table <- gtable_add_cols(table, spacing * missing_cols) 96 | } 97 | table 98 | } 99 | ) 100 | -------------------------------------------------------------------------------- /R/facet_row.R: -------------------------------------------------------------------------------- 1 | #' One-dimensional facets 2 | #' 3 | #' These facets are one-dimensional versions of [ggplot2::facet_wrap()], 4 | #' arranging the panels in either a single row or a single column. This 5 | #' restriction makes it possible to support a `space` argument as seen in 6 | #' [ggplot2::facet_grid()] which, if set to `"free"` will allow the panels to be 7 | #' sized based on the relative range of their scales. Another way of thinking 8 | #' about them are one-dimensional versions of [ggplot2::facet_grid()] (ie. 9 | #' `. ~ {var}` or `{var} ~ .`), but with the ability to position the strip at 10 | #' either side of the panel. However you look at it it is the best of both world 11 | #' if you just need one dimension. 12 | #' 13 | #' @inheritParams ggplot2::facet_wrap 14 | #' @param space Should the size of the panels be fixed or relative to the range 15 | #' of the respective position scales 16 | #' 17 | #' @export 18 | #' 19 | #' @examples 20 | #' # Standard use 21 | #' ggplot(mtcars) + 22 | #' geom_point(aes(disp, mpg)) + 23 | #' facet_col(~gear) 24 | #' # It retains the ability to have unique scales for each panel 25 | #' ggplot(mtcars) + 26 | #' geom_point(aes(disp, mpg)) + 27 | #' facet_col(~gear, scales = 'free') 28 | #' 29 | #' # But can have free sizing along the stacking dimension 30 | #' ggplot(mtcars) + 31 | #' geom_point(aes(disp, mpg)) + 32 | #' facet_col(~gear, scales = 'free', space = 'free') 33 | #' 34 | #' # And you can position the strip where-ever you like 35 | #' ggplot(mtcars) + 36 | #' geom_point(aes(disp, mpg)) + 37 | #' facet_col(~gear, scales = 'free', space = 'free', strip.position = 'bottom') 38 | #' 39 | facet_row <- function(facets, scales = "fixed", space = "fixed", 40 | shrink = TRUE, labeller = "label_value", 41 | drop = TRUE, strip.position = 'top') { 42 | space <- match.arg(space, c('free', 'fixed')) 43 | facet <- facet_wrap(facets, nrow = 1, scales = scales, shrink = shrink, labeller = labeller, drop = drop, strip.position = strip.position) 44 | params <- facet$params 45 | 46 | if ("space" %in% fn_fmls_names(facet_wrap)) { 47 | params$space_free <- list(x = space == 'free', y = FALSE) 48 | } else { 49 | params$space_free <- space == 'free' 50 | } 51 | 52 | ggproto(NULL, FacetRow, shrink = shrink, params = params) 53 | } 54 | #' @rdname ggforce-extensions 55 | #' @format NULL 56 | #' @usage NULL 57 | #' @export 58 | FacetRow <- ggproto('FacetRow', FacetWrap, 59 | draw_panels = function(self, panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) { 60 | combined <- ggproto_parent(FacetWrap, self)$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) 61 | if (isTRUE(params$space_free)) { 62 | widths <- vapply(layout$PANEL, function(i) diff(ranges[[i]]$x.range), numeric(1)) 63 | panel_widths <- unit(widths, "null") 64 | combined$widths[panel_cols(combined)$l] <- panel_widths 65 | } 66 | combined 67 | } 68 | ) 69 | 70 | #' @rdname facet_row 71 | #' @export 72 | facet_col <- function(facets, scales = "fixed", space = "fixed", 73 | shrink = TRUE, labeller = "label_value", 74 | drop = TRUE, strip.position = 'top') { 75 | space <- match.arg(space, c('free', 'fixed')) 76 | facet <- facet_wrap(facets, ncol = 1, scales = scales, shrink = shrink, labeller = labeller, drop = drop, strip.position = strip.position) 77 | params <- facet$params 78 | 79 | if ("space" %in% fn_fmls_names(facet_wrap)) { 80 | params$space_free <- list(x = FALSE, y = space == 'free') 81 | } else { 82 | params$space_free <- space == 'free' 83 | } 84 | ggproto(NULL, FacetCol, shrink = shrink, params = params) 85 | } 86 | #' @rdname ggforce-extensions 87 | #' @format NULL 88 | #' @usage NULL 89 | #' @export 90 | FacetCol <- ggproto('FacetCol', FacetWrap, 91 | draw_panels = function(self, panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) { 92 | combined <- ggproto_parent(FacetWrap, self)$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) 93 | if (isTRUE(params$space_free)) { 94 | heights <- vapply(layout$PANEL, function(i) diff(ranges[[i]]$y.range), numeric(1)) 95 | panel_heights <- unit(heights, "null") 96 | combined$heights[panel_rows(combined)$t] <- panel_heights 97 | } 98 | combined 99 | } 100 | ) 101 | -------------------------------------------------------------------------------- /R/ggforce-package.R: -------------------------------------------------------------------------------- 1 | #' @useDynLib ggforce 2 | #' @import ggplot2 3 | #' 4 | #' @examples 5 | #' rocketData <- data.frame( 6 | #' x = c(1, 1, 2, 2), 7 | #' y = c(1, 2, 2, 3) 8 | #' ) 9 | #' rocketData <- do.call(rbind, lapply(seq_len(500) - 1, function(i) { 10 | #' rocketData$y <- rocketData$y - c(0, i / 500) 11 | #' rocketData$group <- i + 1 12 | #' rocketData 13 | #' })) 14 | #' rocketData2 <- data.frame( 15 | #' x = c(2, 2.25, 2), 16 | #' y = c(2, 2.5, 3) 17 | #' ) 18 | #' rocketData2 <- do.call(rbind, lapply(seq_len(500) - 1, function(i) { 19 | #' rocketData2$x[2] <- rocketData2$x[2] - i * 0.25 / 500 20 | #' rocketData2$group <- i + 1 + 500 21 | #' rocketData2 22 | #' })) 23 | #' 24 | #' ggplot() + geom_link(aes( 25 | #' x = 2, y = 2, xend = 3, yend = 3, alpha = after_stat(index), 26 | #' size = after_stat(index) 27 | #' ), colour = 'goldenrod', n = 500) + 28 | #' geom_bezier(aes(x = x, y = y, group = group, colour = after_stat(index)), 29 | #' data = rocketData 30 | #' ) + 31 | #' geom_bezier(aes(x = y, y = x, group = group, colour = after_stat(index)), 32 | #' data = rocketData 33 | #' ) + 34 | #' geom_bezier(aes(x = x, y = y, group = group, colour = 1), 35 | #' data = rocketData2 36 | #' ) + 37 | #' geom_bezier(aes(x = y, y = x, group = group, colour = 1), 38 | #' data = rocketData2 39 | #' ) + 40 | #' geom_text(aes(x = 1.65, y = 1.65, label = 'ggplot2', angle = 45), 41 | #' colour = 'white', size = 15 42 | #' ) + 43 | #' coord_fixed() + 44 | #' scale_x_reverse() + 45 | #' scale_y_reverse() + 46 | #' scale_alpha(range = c(1, 0), guide = 'none') + 47 | #' scale_size_continuous( 48 | #' range = c(20, 0.1), trans = 'exp', 49 | #' guide = 'none' 50 | #' ) + 51 | #' scale_color_continuous(guide = 'none') + 52 | #' xlab('') + ylab('') + 53 | #' ggtitle('ggforce: Accelerating ggplot2') + 54 | #' theme(plot.title = element_text(size = 20)) 55 | #' @keywords internal 56 | "_PACKAGE" 57 | 58 | ## usethis namespace: start 59 | #' @import rlang 60 | #' @import vctrs 61 | #' @importFrom lifecycle deprecated 62 | #' @useDynLib ggforce, .registration = TRUE 63 | ## usethis namespace: end 64 | NULL 65 | -------------------------------------------------------------------------------- /R/ggproto-classes.R: -------------------------------------------------------------------------------- 1 | #' ggforce extensions to ggplot2 2 | #' 3 | #' ggforce makes heavy use of the ggproto class system to extend the 4 | #' functionality of ggplot2. In general the actual classes should be of little 5 | #' interest to users as the standard ggplot2 api of using geom_* and stat_* 6 | #' functions for building up the plot is encouraged. 7 | #' 8 | #' @name ggforce-extensions 9 | #' @rdname ggforce-extensions 10 | #' 11 | NULL 12 | -------------------------------------------------------------------------------- /R/interpolate.R: -------------------------------------------------------------------------------- 1 | #' @rdname ggforce-extensions 2 | #' @format NULL 3 | #' @usage NULL 4 | #' @importFrom grid segmentsGrob polylineGrob gpar 5 | GeomPathInterpolate <- ggproto('GeomPathInterpolate', GeomPath, 6 | draw_panel = function(self, data, panel_scales, coord, arrow = NULL, 7 | lineend = 'butt', linejoin = 'round', linemitre = 1, 8 | na.rm = FALSE) { 9 | if (!anyDuplicated(data$group)) { 10 | cli::cli_inform(c( 11 | "{.fn {snake_class(self)}}: Each group consists of only one observation.", 12 | i = "Do you need to adjust the {.field group} aesthetic?" 13 | )) 14 | } 15 | data <- data[order(data$group), , drop = FALSE] 16 | data <- interpolateDataFrame(data) 17 | munched <- coord_munch(coord, data, panel_scales) 18 | rows <- stats::ave(seq_len(nrow(munched)), munched$group, 19 | FUN = length 20 | ) 21 | munched <- munched[rows >= 2, ] 22 | if (nrow(munched) < 2) { 23 | return(zeroGrob()) 24 | } 25 | attr <- dapply(data, 'group', function(df) { 26 | data_frame0( 27 | solid = identical(unique0(df$linetype), 1), 28 | constant = nrow(unique0(df[, names(df) %in% c( 29 | 'alpha', 'colour', 30 | 'linewidth', 'size', 'linetype' 31 | )])) == 1 32 | ) 33 | }) 34 | 35 | solid_lines <- all(attr$solid) 36 | constant <- all(attr$constant) 37 | if (!solid_lines && !constant) { 38 | cli::cli_abort("{.fn {snake_class(self)}} can't have varying {.field colour}, {.field linewidth}, and/or {.field alpha} along the line when {.field linetype} isn't solid") 39 | } 40 | n <- nrow(munched) 41 | group_diff <- munched$group[-1] != munched$group[-n] 42 | start <- c(TRUE, group_diff) 43 | end <- c(group_diff, TRUE) 44 | if (!constant) { 45 | segmentsGrob(munched$x[!end], munched$y[!end], munched$x[!start], 46 | munched$y[!start], 47 | default.units = 'native', arrow = arrow, 48 | gp = gpar( 49 | col = alpha(munched$colour, munched$alpha)[!end], 50 | fill = ggplot2::fill_alpha(munched$colour[!end], munched$alpha[!end]), 51 | lwd = (munched$linewidth[!end] %||% munched$size[!end]) * .pt, 52 | lty = munched$linetype[!end], 53 | lineend = lineend, linejoin = linejoin, linemitre = linemitre 54 | ) 55 | ) 56 | } 57 | else { 58 | id <- match(munched$group, unique0(munched$group)) 59 | polylineGrob(munched$x, munched$y, 60 | id = id, default.units = 'native', 61 | arrow = arrow, gp = gpar( 62 | col = alpha(munched$colour, munched$alpha)[start], 63 | fill = ggplot2::fill_alpha(munched$colour[start], munched$alpha[start]), 64 | lwd = (munched$linewidth[start] %||% munched$size[start]) * .pt, 65 | lty = munched$linetype[start], lineend = lineend, 66 | linejoin = linejoin, linemitre = linemitre 67 | ) 68 | ) 69 | } 70 | }, 71 | handle_na = function(data, params) { 72 | data 73 | } 74 | ) 75 | #' Interpolate layer data 76 | #' 77 | #' @param data A data.frame with data for a layer 78 | #' 79 | #' @return A similar data.frame with NA values interpolated 80 | #' 81 | #' @importFrom tweenr tween_t 82 | #' @keywords internal 83 | #' @export 84 | interpolateDataFrame <- function(data) { 85 | if (is.null(data$group)) { 86 | cli::cli_abort('data must have a group column') 87 | } 88 | interpLengths <- lengths(split(data$group, data$group)) 89 | for (i in seq_len(ncol(data))) { 90 | if (names(data)[i] %in% c('x', 'y', 'index', 'group', '.interp') || 91 | all(is.na(data[[i]]))) { 92 | next 93 | } 94 | if (length(unique0(data[[i]][data$.interp])) > 1) { 95 | next 96 | } 97 | interpValues <- split(data[[i]][!data$.interp], data$group[!data$.interp]) 98 | data[[i]] <- unlist(tween_t(interpValues, interpLengths)) 99 | } 100 | data[, names(data) != '.interp'] 101 | } 102 | -------------------------------------------------------------------------------- /R/labeller.R: -------------------------------------------------------------------------------- 1 | #' A labeller function to parse TeX syntax 2 | #' 3 | #' This function formats the strip labels of facet grids and wraps that contains 4 | #' TeX expressions. The latex2exp package must be installed. 5 | #' 6 | #' @seealso [ggplot2::labeller], [latex2exp::TeX()] 7 | #' 8 | #' @inheritParams ggplot2::label_parsed 9 | #' @inheritDotParams ggplot2::label_parsed -labels 10 | #' 11 | #' @examples 12 | #' # requires latex2exp package be installed 13 | #' if (requireNamespace("latex2exp", quietly = TRUE)) { 14 | #' library(ggplot2) 15 | #' d <- data.frame(x = 1, y = 1, facet = "$\\beta$") 16 | #' ggplot(d, aes(x, y)) + 17 | #' geom_point() + 18 | #' facet_wrap(~ facet, labeller = label_tex) 19 | #' } 20 | #' @importFrom ggplot2 label_parsed 21 | #' @export 22 | label_tex <- function(labels, ...) { 23 | check_installed('latex2exp', 'to parse tex equations') 24 | label_parsed( 25 | data_frame0(!!!lapply(labels, latex2exp::TeX, output = "character")), 26 | ... 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /R/position-jitternormal.R: -------------------------------------------------------------------------------- 1 | #' Jitter points with normally distributed random noise 2 | #' 3 | #' [ggplot2::geom_jitter()] adds random noise to points using a uniform 4 | #' distribution. When many points are plotted, they appear in a rectangle. This 5 | #' position jitters points using a normal distribution instead, resulting in 6 | #' more circular clusters. 7 | #' 8 | #' @family position adjustments 9 | #' @param sd_x,sd_y Standard deviation to add along the x and y axes. The 10 | #' function uses [stats::rnorm()] with `mean = 0` behind the scenes. 11 | #' 12 | #' If omitted, defaults to 0.15. As with [ggplot2::geom_jitter()], categorical 13 | #' data is aligned on the integers, so a standard deviation of more than 0.2 14 | #' will spread the data so it's not possible to see the distinction between 15 | #' the categories. 16 | #' @inheritParams ggplot2::position_jitter 17 | #' @export 18 | #' @examples 19 | #' # Example data 20 | #' df <- data.frame( 21 | #' x = sample(1:3, 1500, TRUE), 22 | #' y = sample(1:3, 1500, TRUE) 23 | #' ) 24 | #' 25 | #' # position_jitter results in rectangular clusters 26 | #' ggplot(df, aes(x = x, y = y)) + 27 | #' geom_point(position = position_jitter()) 28 | #' 29 | #' # geom_jitternormal results in more circular clusters 30 | #' ggplot(df, aes(x = x, y = y)) + 31 | #' geom_point(position = position_jitternormal()) 32 | #' 33 | #' # You can adjust the standard deviations along both axes 34 | #' # Tighter circles 35 | #' ggplot(df, aes(x = x, y = y)) + 36 | #' geom_point(position = position_jitternormal(sd_x = 0.08, sd_y = 0.08)) 37 | #' 38 | #' # Oblong shapes 39 | #' ggplot(df, aes(x = x, y = y)) + 40 | #' geom_point(position = position_jitternormal(sd_x = 0.2, sd_y = 0.08)) 41 | #' 42 | #' # Only add random noise to one dimension 43 | #' ggplot(df, aes(x = x, y = y)) + 44 | #' geom_point( 45 | #' position = position_jitternormal(sd_x = 0.15, sd_y = 0), 46 | #' alpha = 0.1 47 | #' ) 48 | position_jitternormal <- function(sd_x = NULL, sd_y = NULL, seed = NA) { 49 | ggproto(NULL, PositionJitterNormal, 50 | sd_x = sd_x, 51 | sd_y = sd_y, 52 | seed = seed 53 | ) 54 | } 55 | #' @rdname ggforce-extensions 56 | #' @format NULL 57 | #' @usage NULL 58 | #' @export 59 | PositionJitterNormal <- ggproto('PositionJitterNormal', 60 | Position, 61 | seed = NA, 62 | required_aes = c('x', 'y'), 63 | 64 | setup_params = function(self, data) { 65 | if (!is.null(self$seed) && is.na(self$seed)) { 66 | seed <- sample.int(.Machine$integer.max, 1L) 67 | } else { 68 | seed <- self$seed 69 | } 70 | list( 71 | sd_x = self$sd_x %||% 0.15, 72 | sd_y = self$sd_y %||% 0.15, 73 | seed = seed 74 | ) 75 | }, 76 | 77 | compute_layer = function(data, params, panel) { 78 | trans_x <- if (params$sd_x > 0) { 79 | function(x) x + rnorm(length(x), sd = params$sd_x) 80 | } 81 | trans_y <- if (params$sd_y > 0) { 82 | function(x) x + rnorm(length(x), sd = params$sd_y) 83 | } 84 | 85 | # Make sure x and y jitter is only calculated once for all position aesthetics 86 | # Takes aesthetic names from ggplot_global 87 | x_aes <- intersect(c("x", "xmin", "xmax", "xend", "xintercept", "xmin_final", "xmax_final", 88 | "xlower", "xmiddle", "xupper", "x0"), names(data)) 89 | x <- if (length(x_aes) == 0) 0 else data[[x_aes[1]]] 90 | y_aes <- intersect(c("y", "ymin", "ymax", "yend", "yintercept", "ymin_final", "ymax_final", 91 | "lower", "middle", "upper", "y0"), names(data)) 92 | y <- if (length(y_aes) == 0) 0 else data[[y_aes[1]]] 93 | dummy_data <- data_frame0(x = x, y = y, .size = nrow(data)) 94 | fixed_jitter <- with_seed_null(params$seed, transform_position(dummy_data, trans_x, trans_y)) 95 | x_jit <- fixed_jitter$x - x 96 | y_jit <- fixed_jitter$y - y 97 | # Avoid nan values, if x or y has Inf values 98 | x_jit[is.infinite(x)] <- 0 99 | y_jit[is.infinite(y)] <- 0 100 | 101 | # Apply jitter 102 | transform_position(data, function(x) x + x_jit, function(x) x + y_jit) 103 | } 104 | ) 105 | -------------------------------------------------------------------------------- /R/position_auto.R: -------------------------------------------------------------------------------- 1 | #' Jitter based on scale types 2 | #' 3 | #' This position adjustment is able to select a meaningful jitter of the data 4 | #' based on the combination of positional scale types. IT behaves differently 5 | #' depending on if none, one, or both the x and y scales are discrete. If both 6 | #' are discrete it will jitter the datapoints evenly inside a disc, if one of 7 | #' them is discrete it will jitter the discrete dimension to follow the density 8 | #' along the other dimension (like a sina plot). If neither are discrete it will 9 | #' not do any jittering. 10 | #' 11 | #' @param jitter.width The maximal width of the jitter 12 | #' @param bw The smoothing bandwidth to use in the case of sina jittering. See 13 | #' the `bw` argument in [stats::density] 14 | #' @param scale Should the width of jittering be scaled based on the number of 15 | #' points in the group 16 | #' @param seed A seed to supply to make the jittering reproducible across layers 17 | #' 18 | #' @seealso [geom_autopoint] for a point geom that uses auto-position by default 19 | #' 20 | #' @export 21 | #' 22 | #' @examples 23 | #' # Continuous vs continuous: No jitter 24 | #' ggplot(mpg) + geom_point(aes(cty, hwy), position = 'auto') 25 | #' 26 | #' # Continuous vs discrete: sina jitter 27 | #' ggplot(mpg) + geom_point(aes(cty, drv), position = 'auto') 28 | #' 29 | #' # Discrete vs discrete: disc-jitter 30 | #' ggplot(mpg) + geom_point(aes(fl, drv), position = 'auto') 31 | #' 32 | #' # Don't scale the jitter based on group size 33 | #' ggplot(mpg) + geom_point(aes(cty, drv), position = position_auto(scale = FALSE)) 34 | #' ggplot(mpg) + geom_point(aes(fl, drv), position = position_auto(scale = FALSE)) 35 | #' 36 | position_auto <- function(jitter.width = 0.75, bw = 'nrd0', scale = TRUE, seed = NA) { 37 | if (!is.null(seed) && is.na(seed)) { 38 | seed <- sample.int(.Machine$integer.max, 1L) 39 | } 40 | 41 | ggproto(NULL, PositionAuto, 42 | jitter.width = jitter.width, 43 | seed = seed, bw = bw, scale = scale 44 | ) 45 | } 46 | #' @rdname ggforce-extensions 47 | #' @format NULL 48 | #' @usage NULL 49 | #' @export 50 | #' @importFrom withr with_seed 51 | PositionAuto <- ggproto('PositionAuto', Position, 52 | jitter.width = 0.75, 53 | seed = NULL, 54 | bw = 'nrd0', 55 | scale = TRUE, 56 | setup_params = function(self, data) { 57 | list(jitter.width = self$jitter.width, bw = self$bw, seed = self$seed, scale = self$scale) 58 | }, 59 | compute_panel = function(data, params, scales) { 60 | discrete_x <- scales$x$is_discrete() 61 | discrete_y <- scales$y$is_discrete() 62 | if (!discrete_x && !discrete_y) { 63 | return(data) 64 | } 65 | if (discrete_x && discrete_y) { 66 | comb <- table(data$x, data$y) 67 | max_n <- max(comb) 68 | if (params$scale) { 69 | weight <- sqrt(comb[cbind(as.character(data$x), as.character(data$y))] / max_n) * (params$jitter.width / 2) 70 | } else { 71 | weight <- params$jitter.width / 2 72 | } 73 | if (is.null(params$seed)) { 74 | adj <- sample_disc(length(data$x), weight) 75 | } else { 76 | adj <- with_seed(params$seed, sample_disc(length(data$x), weight)) 77 | } 78 | data$x <- data$x + adj$x 79 | data$y <- data$y + adj$y 80 | data 81 | } else { 82 | trans_x <- trans_y <- identity 83 | if (discrete_x) { 84 | trans_x <- function(x) x + sina_trans(x, data$y, params$jitter.width / 2, params$bw, params$scale) 85 | } else { 86 | trans_y <- function(x) x + sina_trans(x, data$x, params$jitter.width / 2, params$bw, params$scale) 87 | } 88 | if (is.null(params$seed)) { 89 | transform_position(data, trans_x, trans_y) 90 | } else { 91 | with_seed(params$seed, transform_position(data, trans_x, trans_y)) 92 | } 93 | } 94 | } 95 | ) 96 | 97 | sina_trans <- function(x, val, max_width, bw = 'nrd0', scale = TRUE) { 98 | max_size <- max(table(x)) 99 | by_ind <- split(seq_along(x), x) 100 | x_new <- unlist(lapply(by_ind, function(i) { 101 | val_x <- val[i] 102 | if (length(unique0(val_x)) < 2) { 103 | return(stats::runif(length(val_x), min = -max_width, max = max_width)) 104 | } 105 | if (length(val_x) < 3) { 106 | return(0) 107 | } 108 | range <- range(val_x, na.rm = TRUE) 109 | bw <- calc_bw(val_x, bw) 110 | dens <- stats::density(val_x, bw = bw, from = range[1], to = range[2]) 111 | densf <- stats::approxfun(dens$x, dens$y, rule = 2) 112 | x_mod <- densf(val_x) 113 | x_mod <- x_mod / max(x_mod) 114 | if (scale) x_mod <- x_mod * length(val_x) / max_size 115 | stats::runif(length(val_x), min = -1, max = 1) * max_width * x_mod 116 | })) 117 | x_new[match(seq_along(x), unlist(by_ind))] 118 | } 119 | sample_disc <- function(n, r_disc = 1) { 120 | r = sqrt(stats::runif(n, 0, 1)) 121 | theta = stats::runif(n, 0, 2*pi) 122 | x <- r * cos(theta) * r_disc 123 | y <- r * sin(theta) * r_disc 124 | list(x = x, y = y) 125 | } 126 | -------------------------------------------------------------------------------- /R/position_floatstack.R: -------------------------------------------------------------------------------- 1 | # Only for use with autohistogram and autodensity 2 | 3 | #' @rdname ggforce-extensions 4 | #' @format NULL 5 | #' @usage NULL 6 | #' @export 7 | PositionFloatstack <- ggproto('PositionFloatstack', PositionStack, 8 | setup_params = function(self, data) { 9 | flipped_aes <- has_flipped_aes(data) 10 | data <- flip_data(data, flipped_aes) 11 | list( 12 | var = self$var %||% if (flipped_aes) 'xmax' else 'ymax', 13 | fill = self$fill, 14 | vjust = self$vjust, 15 | reverse = self$reverse, 16 | flipped_aes = flipped_aes 17 | ) 18 | }, 19 | compute_panel = function(self, data, params, scales) { 20 | data <- flip_data(data, params$flipped_aes) 21 | panel_min <- data$ymin[1] 22 | 23 | data$y <- data$y - panel_min 24 | data$ymin <- data$ymin - panel_min 25 | data$ymax <- data$ymax - panel_min 26 | 27 | data <- flip_data(data, params$flipped_aes) 28 | data <- ggproto_parent(PositionStack, self)$compute_panel(data, params, scales) 29 | data <- flip_data(data, params$flipped_aes) 30 | 31 | data$y <- data$y + panel_min 32 | data$ymin <- data$ymin + panel_min 33 | data$ymax <- data$ymax + panel_min 34 | 35 | flip_data(data, params$flipped_aes) 36 | } 37 | ) 38 | -------------------------------------------------------------------------------- /R/regon.R: -------------------------------------------------------------------------------- 1 | #' Draw regular polygons by specifying number of sides 2 | #' 3 | #' This geom makes it easy to construct regular polygons (polygons where all 4 | #' sides and angles are equal) by specifying the number of sides, position, and 5 | #' size. The polygons are always rotated so that they "rest" on a flat side, but 6 | #' this can be changed with the angle aesthetic. The size is based on the radius 7 | #' of their circumcircle and is thus not proportional to their area. 8 | #' 9 | #' @section Aesthetics: 10 | #' geom_regon understand the following aesthetics (required aesthetics are in 11 | #' bold): 12 | #' 13 | #' - **x0** x coordinate 14 | #' - **y0** y coordinate 15 | #' - **sides** the number of sides for regon 16 | #' - **r** the ratio of regon with respect to plot 17 | #' - **angle** regon rotation angle (unit is radian) 18 | #' - color 19 | #' - fill 20 | #' - size 21 | #' - linetype 22 | #' - alpha 23 | #' - lineend 24 | #' 25 | #' @section Computed variables: 26 | #' 27 | #' \describe{ 28 | #' \item{x, y}{The coordinates for the corners of the polygon} 29 | #' } 30 | #' 31 | #' @inheritParams ggplot2::geom_polygon 32 | #' @inheritParams ggplot2::stat_identity 33 | #' 34 | #' @name geom_regon 35 | #' @rdname geom_regon 36 | #' 37 | #' @examples 38 | #' ggplot() + 39 | #' geom_regon(aes(x0 = runif(8), y0 = runif(8), sides = sample(3:10, 8), 40 | #' angle = 0, r = runif(8) / 10)) + 41 | #' coord_fixed() 42 | #' 43 | #' # The polygons are drawn with geom_shape, so can be manipulated as such 44 | #' ggplot() + 45 | #' geom_regon(aes(x0 = runif(8), y0 = runif(8), sides = sample(3:10, 8), 46 | #' angle = 0, r = runif(8) / 10), 47 | #' expand = unit(1, 'cm'), radius = unit(1, 'cm')) + 48 | #' coord_fixed() 49 | NULL 50 | 51 | #' @rdname ggforce-extensions 52 | #' @format NULL 53 | #' @usage NULL 54 | #' @export 55 | StatRegon <- ggproto('StatRegon', Stat, 56 | compute_layer = function(self, data, params, panels) { 57 | if (empty_data(data)) return(data) 58 | pos <- unlist(lapply(data$sides, function(n) { 59 | p <- (seq_len(n) - 1) / n 60 | if (n %% 2 == 0) p <- p + p[2] / 2 61 | p * 2 * pi 62 | })) 63 | data$group <- make_unique(data$group) 64 | data <- data[rep(seq_len(nrow(data)), data$sides), ] 65 | x_tmp <- sin(pos) * data$r 66 | y_tmp <- cos(pos) * data$r 67 | data$x <- data$x0 + x_tmp * cos(data$angle) - y_tmp * sin(data$angle) 68 | data$y <- data$y0 + x_tmp * sin(data$angle) + y_tmp * cos(data$angle) 69 | data 70 | }, 71 | required_aes = c('x0', 'y0', 'sides', 'angle', 'r'), 72 | extra_params = c('na.rm') 73 | ) 74 | 75 | #' @rdname geom_regon 76 | #' @export 77 | stat_regon <- function(mapping = NULL, data = NULL, geom = 'shape', 78 | position = 'identity', na.rm = FALSE, show.legend = NA, 79 | inherit.aes = TRUE, ...) { 80 | layer( 81 | stat = StatRegon, data = data, mapping = mapping, geom = geom, 82 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 83 | params = list2(na.rm = na.rm, ...) 84 | ) 85 | } 86 | #' @rdname geom_regon 87 | #' @export 88 | geom_regon <- function(mapping = NULL, data = NULL, stat = 'regon', 89 | position = 'identity', na.rm = FALSE, 90 | show.legend = NA, inherit.aes = TRUE, ...) { 91 | layer( 92 | data = data, mapping = mapping, stat = stat, geom = GeomShape, 93 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 94 | params = list2(na.rm = na.rm, ...) 95 | ) 96 | } 97 | -------------------------------------------------------------------------------- /R/scale-depth.R: -------------------------------------------------------------------------------- 1 | #' Scales for depth perception 2 | #' 3 | #' These scales serve to scale the depth aesthetic when creating stereographic 4 | #' plots. The range specifies the relative distance between the points and the 5 | #' paper plane in relation to the distance between the eyes and the paper plane 6 | #' i.e. a range of c(-0.5, 0.5) would put the highest values midways between 7 | #' the eyes and the image plane and the lowest values the same distance behind 8 | #' the image plane. To ensure a nice viewing experience these values should not 9 | #' exceed ~0.3 as it would get hard for the eyes to consolidate the two 10 | #' pictures. 11 | #' 12 | #' @param ... arguments passed on to continuous_scale or discrete_scale 13 | #' 14 | #' @param range The relative range as related to the distance between the eyes 15 | #' and the paper plane. 16 | #' 17 | #' @export 18 | #' @importFrom scales rescale_pal 19 | #' 20 | #' @examples 21 | #' ggplot(mtcars) + 22 | #' geom_point(aes(mpg, disp, depth = cyl)) + 23 | #' scale_depth(range = c(-0.1, 0.25)) + 24 | #' facet_stereo() 25 | scale_depth <- function(..., range = c(0, 0.3)) { 26 | continuous_scale('depth', 'depth_c', rescale_pal(range), ...) 27 | } 28 | 29 | #' @rdname scale_depth 30 | #' 31 | #' @export 32 | scale_depth_continuous <- scale_depth 33 | 34 | #' @rdname scale_depth 35 | #' 36 | #' @export 37 | scale_depth_discrete <- function(..., range = c(0, 0.3)) { 38 | discrete_scale( 39 | 'depth', 'depth_d', 40 | function(n) seq(range[1], range[2], length.out = n), ... 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /R/scale-unit.R: -------------------------------------------------------------------------------- 1 | #' Position scales for units data 2 | #' 3 | #' `r lifecycle::badge('deprecated')` These are the default scales for the units 4 | #' class. These will usually be added automatically. To override manually, use 5 | #' `scale_*_unit`. 6 | #' 7 | #' @param ... Passed on to `units::scale_x_units()` or `units::scale_y_units()` 8 | #' 9 | #' @name scale_unit 10 | #' @aliases NULL 11 | #' @keywords internal 12 | NULL 13 | 14 | #' @rdname scale_unit 15 | #' @export 16 | #' @importFrom scales censor 17 | scale_x_unit <- function(...) { 18 | lifecycle::deprecate_soft('0.3.4', "scale_x_unit()", "units::scale_x_units()") 19 | check_installed('units', 'to use scale_x_unit') 20 | units::scale_x_units(...) 21 | } 22 | #' @rdname scale_unit 23 | #' @export 24 | #' @importFrom scales censor 25 | scale_y_unit <- function(...) { 26 | lifecycle::deprecate_soft('0.3.4', "scale_y_unit()", "units::scale_y_units()") 27 | check_installed('units', 'to use scale_y_unit') 28 | units::scale_y_units(...) 29 | } 30 | -------------------------------------------------------------------------------- /R/spiro.R: -------------------------------------------------------------------------------- 1 | #' Draw spirograms based on the radii of the different "wheels" involved 2 | #' 3 | #' This, rather pointless, geom allows you to draw spirograms, as known from the 4 | #' popular drawing toy where lines were traced by inserting a pencil into a hole 5 | #' in a small gear that would then trace around inside another gear. The 6 | #' potential practicality of this geom is slim and it excists mainly for fun and 7 | #' art. 8 | #' 9 | #' @section Aesthetics: 10 | #' stat_spiro and geom_spiro understand the following aesthetics (required 11 | #' aesthetics are in bold): 12 | #' 13 | #' - **R** 14 | #' - **r** 15 | #' - **d** 16 | #' - x0 17 | #' - y0 18 | #' - outer 19 | #' - color 20 | #' - size 21 | #' - linetype 22 | #' - alpha 23 | #' 24 | #' @section Computed variables: 25 | #' 26 | #' \describe{ 27 | #' \item{x, y}{The coordinates for the path describing the spirogram} 28 | #' \item{index}{The progression along the spirogram mapped between 0 and 1} 29 | #' } 30 | #' 31 | #' @inheritParams ggplot2::geom_path 32 | #' @inheritParams ggplot2::stat_identity 33 | #' 34 | #' @param n The number of points that should be used to draw a fully closed 35 | #' spirogram. If `revolutions < 1` the actual number of points will be less 36 | #' than this. 37 | #' 38 | #' @param revolutions The number of times the inner gear should revolve around 39 | #' inside the outer gear. If `NULL` the number of revolutions to reach the 40 | #' starting position is calculated and used. 41 | #' 42 | #' @name geom_spiro 43 | #' @rdname geom_spiro 44 | #' 45 | #' @examples 46 | #' # Basic usage 47 | #' ggplot() + 48 | #' geom_spiro(aes(R = 10, r = 3, d = 5)) 49 | #' 50 | #' # Only draw a portion 51 | #' ggplot() + 52 | #' geom_spiro(aes(R = 10, r = 3, d = 5), revolutions = 1.2) 53 | #' 54 | #' # Let the inner gear circle the outside of the outer gear 55 | #' ggplot() + 56 | #' geom_spiro(aes(R = 10, r = 3, d = 5, outer = TRUE)) 57 | NULL 58 | 59 | #' @rdname ggforce-extensions 60 | #' @format NULL 61 | #' @usage NULL 62 | #' @importFrom MASS fractions 63 | #' @export 64 | StatSpiro <- ggproto('StatSpiro', Stat, 65 | compute_panel = function(data, scales, n = 500, revolutions = NULL) { 66 | if (empty_data(data)) return(data) 67 | if (is.null(data$outer)) data$outer <- FALSE 68 | if (is.null(data$x0)) data$x0 <- 0 69 | if (is.null(data$y0)) data$y0 <- 0 70 | n_spiro <- nrow(data) 71 | data$group <- make_unique(data$group) 72 | if (is.null(revolutions)) { 73 | revo <- attr(fractions(data$r / data$R), 'fracs') 74 | revo <- as.numeric(sub('/.*$', '', revo)) 75 | } else { 76 | revo <- revolutions 77 | } 78 | data <- data[rep(seq_len(n_spiro), n * revo), ] 79 | data$rho <- unlist(lapply(revo, function(r) { 80 | seq(0, 2 * pi * r, length.out = n * r) 81 | })) 82 | data$index <- unlist(lapply(revo, function(r) { 83 | seq(0, 1, length.out = n * r) 84 | })) 85 | data$x <- data$x0 + ifelse( 86 | data$outer, 87 | (data$R + data$r) * cos(data$rho) - data$d * cos(data$rho * (data$R + data$r) / data$r), 88 | (data$R - data$r) * cos(data$rho) + data$d * cos(data$rho * (data$R - data$r) / data$r) 89 | ) 90 | data$y <- data$y0 + ifelse( 91 | data$outer, 92 | (data$R + data$r) * sin(data$rho) - data$d * sin(data$rho * (data$R + data$r) / data$r), 93 | (data$R - data$r) * sin(data$rho) - data$d * sin(data$rho * (data$R - data$r) / data$r) 94 | ) 95 | data 96 | }, 97 | required_aes = c('R', 'r', 'd'), 98 | default_aes = aes(outer = FALSE, x0 = 0, y0 = 0), 99 | extra_params = c('na.rm', 'n', 'revolutions') 100 | ) 101 | 102 | #' @rdname geom_spiro 103 | #' @export 104 | stat_spiro <- function(mapping = NULL, data = NULL, geom = 'path', 105 | position = 'identity', na.rm = FALSE, n = 500, 106 | revolutions = NULL, show.legend = NA, inherit.aes = TRUE, 107 | ...) { 108 | layer( 109 | stat = StatSpiro, data = data, mapping = mapping, geom = geom, 110 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 111 | params = list2(na.rm = na.rm, n = n, revolutions = revolutions, ...) 112 | ) 113 | } 114 | 115 | #' @rdname geom_spiro 116 | #' @export 117 | geom_spiro <- function(mapping = NULL, data = NULL, stat = 'spiro', 118 | position = 'identity', arrow = NULL, n = 500, 119 | lineend = 'butt', na.rm = FALSE, show.legend = NA, 120 | inherit.aes = TRUE, ...) { 121 | layer( 122 | data = data, mapping = mapping, stat = stat, geom = GeomPath, 123 | position = position, show.legend = show.legend, inherit.aes = inherit.aes, 124 | params = list2(arrow = arrow, lineend = lineend, na.rm = na.rm, n = n, ...) 125 | ) 126 | } 127 | -------------------------------------------------------------------------------- /R/themes.R: -------------------------------------------------------------------------------- 1 | #' Theme without axes and gridlines 2 | #' 3 | #' This theme is a simple wrapper around any complete theme that removes the 4 | #' axis text, title and ticks as well as the grid lines for plots where these 5 | #' have little meaning. 6 | #' 7 | #' @param base.theme The theme to use as a base for the new theme. Defaults to 8 | #' [ggplot2::theme_bw()]. 9 | #' 10 | #' @return A modified version of base.theme 11 | #' 12 | #' @export 13 | #' 14 | #' @examples 15 | #' p <- ggplot() + geom_point(aes(x = wt, y = qsec), data = mtcars) 16 | #' 17 | #' p + theme_no_axes() 18 | #' p + theme_no_axes(theme_grey()) 19 | #' 20 | theme_no_axes <- function(base.theme = theme_bw()) { 21 | base.theme %+replace% 22 | theme( 23 | axis.text = element_blank(), 24 | axis.title = element_blank(), 25 | axis.ticks = element_blank(), 26 | panel.grid = element_blank() 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /R/trans_linear.R: -------------------------------------------------------------------------------- 1 | #' Create a custom linear transformation 2 | #' 3 | #' This function lets you compose transformations based on a sequence of linear 4 | #' transformations. If the transformations are parameterised the parameters will 5 | #' become arguments in the transformation function. The transformations are 6 | #' one of `rotate`, `shear`, `stretch`, `translate`, and 7 | #' `reflect`. 8 | #' 9 | #' @param ... A number of transformation functions. 10 | #' 11 | #' @return `linear_trans` creates a trans object. The other functions 12 | #' return a 3x3 transformation matrix. 13 | #' 14 | #' @export 15 | #' @importFrom scales trans_new 16 | #' 17 | #' @examples 18 | #' trans <- linear_trans(rotate(a), shear(1, 0), translate(x1, y1)) 19 | #' square <- data.frame(x = c(0, 0, 1, 1), y = c(0, 1, 1, 0)) 20 | #' square2 <- trans$transform(square$x, square$y, a = pi / 3, x1 = 4, y1 = 8) 21 | #' square3 <- trans$transform(square$x, square$y, a = pi / 1.5, x1 = 2, y1 = -6) 22 | #' square <- rbind(square, square2, square3) 23 | #' square$group <- rep(1:3, each = 4) 24 | #' ggplot(square, aes(x, y, group = group)) + 25 | #' geom_polygon(aes(fill = factor(group)), colour = 'black') 26 | linear_trans <- function(...) { 27 | calls <- as.list(substitute(list2(...)))[-1] 28 | transformations <- sapply(calls, deparse) 29 | args <- unlist(lapply(calls, function(call) { 30 | args <- as.list(call)[-1] 31 | as.character(args[sapply(args, 'class') == 'name']) 32 | })) 33 | args <- unique0(args) 34 | if (any(c('x', 'y') %in% args)) { 35 | cli::cli_abort('{.arg x} and {.arg y} are preserved argument names') 36 | } 37 | args <- c('x', 'y', args) 38 | trans_fun <- function() { 39 | env <- environment() 40 | trans_mat <- Reduce(function(l, r) r %*% l, 41 | lapply(calls, eval, envir = env)) 42 | trans <- trans_mat %*% rbind(x, y, z = 1) 43 | data_frame0(x = trans[1, ], y = trans[2, ]) 44 | } 45 | formals(trans_fun) <- structure(rep(list(quote(expr = )), length(args)), 46 | names = args) 47 | inv_fun <- function() { 48 | env <- environment() 49 | trans_mat <- Reduce(function(l, r) r %*% l, 50 | lapply(calls, eval, envir = env)) 51 | trans_mat <- solve(trans_mat) 52 | trans <- trans_mat %*% rbind(x, y, z = 1) 53 | data_frame0(x = trans[1, ], y = trans[2, ]) 54 | } 55 | formals(inv_fun) <- structure(rep(list(quote(expr = )), length(args)), 56 | names = args) 57 | trans_new( 58 | name = paste0('linear: ', paste(transformations, collapse = ', ')), 59 | transform = trans_fun, 60 | inverse = inv_fun, 61 | breaks = extended_breaks(), 62 | format = format_format() 63 | ) 64 | } 65 | 66 | #' @rdname linear_trans 67 | #' @param angle An angle in radians 68 | rotate <- function(angle) { 69 | matrix(c(cos(angle), -sin(angle), 0, sin(angle), cos(angle), 0, 0, 0, 1), 70 | ncol = 3) 71 | } 72 | #' @rdname linear_trans 73 | #' @param x the transformation magnitude in the x-direction 74 | #' @param y the transformation magnitude in the x-direction 75 | stretch <- function(x, y) { 76 | matrix(c(x, 0, 0, 0, y, 0, 0, 0, 1), ncol = 3) 77 | } 78 | #' @rdname linear_trans 79 | shear <- function(x, y) { 80 | matrix(c(1, y, 0, x, 1, 0, 0, 0, 1), ncol = 3) 81 | } 82 | #' @rdname linear_trans 83 | translate <- function(x, y) { 84 | matrix(c(1, 0, 0, 0, 1, 0, x, y, 1), ncol = 3) 85 | } 86 | #' @rdname linear_trans 87 | reflect <- function(x, y) { 88 | l <- x^2 + y^2 89 | matrix( 90 | c( 91 | (x^2 - y^2) / l, 92 | 2 * x * y / l, 93 | 0, 94 | 2 * x * y / l, 95 | (y^2 - x^2) / l, 96 | 0, 97 | 0, 98 | 0, 99 | 1 100 | ), 101 | ncol = 3 102 | ) 103 | } 104 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | default_axis_guide <- NULL 2 | .onLoad <- function(...) { 3 | if (utils::packageVersion("ggplot2") > "3.2.1") { 4 | default_axis_guide <<- ggplot2::waiver() 5 | } else { 6 | default_axis_guide <<- "none" 7 | } 8 | ggplot2::register_theme_elements( 9 | zoom = element_rect(), 10 | zoom.x = element_rect(), 11 | zoom.y = element_rect(), 12 | element_tree = list( 13 | zoom = ggplot2::el_def('element_rect', 'strip.background'), 14 | zoom.x = ggplot2::el_def('element_rect', 'zoom'), 15 | zoom.y = ggplot2::el_def('element_rect', 'zoom') 16 | ) 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | # ggforce 16 | 17 | 18 | [![R-CMD-check](https://github.com/thomasp85/ggforce/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/thomasp85/ggforce/actions/workflows/R-CMD-check.yaml) 19 | [![CRAN_Release_Badge](http://www.r-pkg.org/badges/version-ago/ggforce)](https://CRAN.R-project.org/package=ggforce) 20 | [![CRAN_Download_Badge](http://cranlogs.r-pkg.org/badges/ggforce)](https://CRAN.R-project.org/package=ggforce) 21 | 22 | 23 | *Accelerating ggplot2* 24 | 25 | `ggforce` is a package aimed at providing missing functionality to `ggplot2` 26 | through the extension system introduced with `ggplot2` v2.0.0. Broadly speaking 27 | `ggplot2` has been aimed primarily at explorative data visualization in order to 28 | investigate the data at hand, and less at providing utilities for composing 29 | custom plots a la [D3.js](https://d3js.org). `ggforce` is mainly an attempt to 30 | address these "shortcomings" (design choices might be a better description). The 31 | goal is to provide a repository of geoms, stats, etc. that are as well 32 | documented and implemented as the official ones found in `ggplot2`. 33 | 34 | ## Installation 35 | 36 | You can install the released version of ggforce from [CRAN](https://CRAN.R-project.org) with: 37 | 38 | ``` r 39 | install.packages("ggforce") 40 | ``` 41 | 42 | And the development version from [GitHub](https://github.com/) with: 43 | 44 | ``` r 45 | # install.packages("devtools") 46 | devtools::install_github("thomasp85/ggforce") 47 | ``` 48 | 49 | ## Features 50 | `ggforce` is by design a collection of features with the only commonality being 51 | their tie to the `ggplot2` API. Because of this an overview of all features 52 | would get too long for a README. The package has a [website](https://ggforce.data-imaginist.com) 53 | where every feature is described and justified with examples and plots. There 54 | should be a plot in the README of a visualization package though, so without 55 | further ado: 56 | 57 | ```{r example} 58 | library(ggforce) 59 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 60 | geom_point() + 61 | facet_zoom(x = Species == "versicolor") 62 | ``` 63 | 64 | ## Code of Conduct 65 | Please note that the 'ggforce' project is released with a 66 | [Contributor Code of Conduct](https://ggforce.data-imaginist.com/CODE_OF_CONDUCT.html). 67 | By contributing to this project, you agree to abide by its terms. 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # ggforce 5 | 6 | 7 | 8 | [![R-CMD-check](https://github.com/thomasp85/ggforce/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/thomasp85/ggforce/actions/workflows/R-CMD-check.yaml) 9 | [![CRAN_Release_Badge](http://www.r-pkg.org/badges/version-ago/ggforce)](https://CRAN.R-project.org/package=ggforce) 10 | [![CRAN_Download_Badge](http://cranlogs.r-pkg.org/badges/ggforce)](https://CRAN.R-project.org/package=ggforce) 11 | 12 | 13 | *Accelerating ggplot2* 14 | 15 | `ggforce` is a package aimed at providing missing functionality to 16 | `ggplot2` through the extension system introduced with `ggplot2` v2.0.0. 17 | Broadly speaking `ggplot2` has been aimed primarily at explorative data 18 | visualization in order to investigate the data at hand, and less at 19 | providing utilities for composing custom plots a la 20 | [D3.js](https://d3js.org). `ggforce` is mainly an attempt to address 21 | these “shortcomings” (design choices might be a better description). The 22 | goal is to provide a repository of geoms, stats, etc. that are as well 23 | documented and implemented as the official ones found in `ggplot2`. 24 | 25 | ## Installation 26 | 27 | You can install the released version of ggforce from 28 | [CRAN](https://CRAN.R-project.org) with: 29 | 30 | ``` r 31 | install.packages("ggforce") 32 | ``` 33 | 34 | And the development version from [GitHub](https://github.com/) with: 35 | 36 | ``` r 37 | # install.packages("devtools") 38 | devtools::install_github("thomasp85/ggforce") 39 | ``` 40 | 41 | ## Features 42 | 43 | `ggforce` is by design a collection of features with the only 44 | commonality being their tie to the `ggplot2` API. Because of this an 45 | overview of all features would get too long for a README. The package 46 | has a [website](https://ggforce.data-imaginist.com) where every feature 47 | is described and justified with examples and plots. There should be a 48 | plot in the README of a visualization package though, so without further 49 | ado: 50 | 51 | ``` r 52 | library(ggforce) 53 | #> Loading required package: ggplot2 54 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 55 | geom_point() + 56 | facet_zoom(x = Species == "versicolor") 57 | ``` 58 | 59 | 60 | 61 | ## Code of Conduct 62 | 63 | Please note that the ‘ggforce’ project is released with a [Contributor 64 | Code of 65 | Conduct](https://ggforce.data-imaginist.com/CODE_OF_CONDUCT.html). By 66 | contributing to this project, you agree to abide by its terms. 67 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | destination: docs 2 | url: https://ggforce.data-imaginist.com 3 | 4 | authors: 5 | Thomas Lin Pedersen: 6 | href: https://data-imaginist.com 7 | 8 | template: 9 | params: 10 | bootswatch: sandstone 11 | 12 | navbar: 13 | left: 14 | - icon: fa-home fa-lg 15 | href: index.html 16 | - text: Reference 17 | href: reference/index.html 18 | - text: News 19 | menu: 20 | - text: "Release notes" 21 | - text: "Version 0.3.0" 22 | href: https://www.data-imaginist.com/2019/a-flurry-of-facets/ 23 | - text: "Version 0.2.0" 24 | href: https://www.data-imaginist.com/2019/the-ggforce-awakens-again/ 25 | - text: "Version 0.1.0" 26 | href: https://www.data-imaginist.com/2016/announcing-ggforce/ 27 | - text: "------------------" 28 | - text: "Change log" 29 | href: news/index.html 30 | right: 31 | - icon: fa-github fa-lg 32 | href: https://github.com/thomasp85/ggforce 33 | 34 | reference: 35 | - title: "Shapes" 36 | desc: > 37 | Shapes are, in essence, anything with volume. These geoms allow you to 38 | draw differnt types of parameterised shapes, all taking advantage of the 39 | benefit of the `geom_shape` improvements to `geom_polygon`. 40 | contents: 41 | - geom_shape 42 | - geom_circle 43 | - geom_ellipse 44 | - geom_regon 45 | - geom_arc_bar 46 | - geom_bspline_closed 47 | - geom_diagonal_wide 48 | - geom_parallel_sets 49 | - geom_voronoi_tile 50 | - title: "Lines" 51 | desc: > 52 | The different line geoms are all parameterised versions of different line 53 | types, greatly easing your pain when needing a special type of stroke. 54 | Many of them have several versions depending on whether you want to show 55 | gradients along the lines, interpolate between endpoint aesthetics, or 56 | simply have a barebone version. 57 | contents: 58 | - geom_link 59 | - geom_arc 60 | - geom_bezier 61 | - geom_bspline 62 | - geom_diagonal 63 | - geom_spiro 64 | - geom_voronoi_segment 65 | - title: "Annotation" 66 | desc: > 67 | Annotation is important for storytelling, and ggforce provides a family of 68 | geoms that makes it easy to draw attention to, and describe, features of 69 | the plot. They all work in the same way, but differ in the way they 70 | enclose the area you want to draw attention to. 71 | contents: 72 | - geom_mark_rect 73 | - geom_mark_circle 74 | - geom_mark_ellipse 75 | - geom_mark_hull 76 | - title: "Facets" 77 | desc: > 78 | Facets are one of the greatest things in ggplot2, and ggforce comes with 79 | more of the awesomeness, both with variants of `facet_grid` and 80 | `facet_wrap`, as well as completely new takes on faceting. 81 | contents: 82 | - facet_matrix 83 | - facet_zoom 84 | - facet_row 85 | - facet_wrap_paginate 86 | - facet_grid_paginate 87 | - facet_stereo 88 | - title: "Scales" 89 | desc: > 90 | While separate packages comes with different palettes for already 91 | established scales, ggforce provides two completely new ones. 92 | contents: 93 | - scale_x_unit 94 | - scale_depth 95 | - title: "Transformations" 96 | desc: > 97 | Transformations can both be used to transform scales and coordinate 98 | systems but can also be used more broadly for describing specific types of 99 | spatial transformation of data. 100 | contents: 101 | - trans_reverser 102 | - power_trans 103 | - radial_trans 104 | - linear_trans 105 | - title: "Misc" 106 | desc: > 107 | ggforce contains an assortment of various stuff that doesn't fit into a 108 | bigger bucket. That doesn't make it any less useful. 109 | contents: 110 | - geom_sina 111 | - geom_autopoint 112 | - geom_autodensity 113 | - label_tex 114 | - stat_err 115 | - position_auto 116 | - position_jitternormal 117 | - gather_set_data 118 | - n_pages 119 | - theme_no_axes 120 | - ggforce-package 121 | - ggforce-extensions 122 | 123 | figures: 124 | dev: grDevices::png 125 | 126 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | Bigger patch release addressing a range of bugs, as well as removing the 2 | concaveman, Rcpp, and RcppEigen dependency in favor of cpp11 3 | 4 | ## revdepcheck results 5 | 6 | We checked 82 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 7 | 8 | * We saw 0 new problems 9 | * We failed to check 0 packages 10 | -------------------------------------------------------------------------------- /man/facet_grid_paginate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/facet_grid_paginate.R 3 | \name{facet_grid_paginate} 4 | \alias{facet_grid_paginate} 5 | \title{Split facet_grid over multiple plots} 6 | \usage{ 7 | facet_grid_paginate( 8 | facets, 9 | margins = FALSE, 10 | scales = "fixed", 11 | space = "fixed", 12 | shrink = TRUE, 13 | labeller = "label_value", 14 | as.table = TRUE, 15 | switch = NULL, 16 | drop = TRUE, 17 | ncol = NULL, 18 | nrow = NULL, 19 | page = 1, 20 | byrow = TRUE 21 | ) 22 | } 23 | \arguments{ 24 | \item{facets}{\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} Please use \code{rows} 25 | and \code{cols} instead.} 26 | 27 | \item{margins}{Either a logical value or a character 28 | vector. Margins are additional facets which contain all the data 29 | for each of the possible values of the faceting variables. If 30 | \code{FALSE}, no additional facets are included (the 31 | default). If \code{TRUE}, margins are included for all faceting 32 | variables. If specified as a character vector, it is the names of 33 | variables for which margins are to be created.} 34 | 35 | \item{scales}{Are scales shared across all facets (the default, 36 | \code{"fixed"}), or do they vary across rows (\code{"free_x"}), 37 | columns (\code{"free_y"}), or both rows and columns (\code{"free"})?} 38 | 39 | \item{space}{If \code{"fixed"}, the default, all panels have the same size. 40 | If \code{"free_y"} their height will be proportional to the length of the 41 | y scale; if \code{"free_x"} their width will be proportional to the 42 | length of the x scale; or if \code{"free"} both height and width will 43 | vary. This setting has no effect unless the appropriate scales also vary.} 44 | 45 | \item{shrink}{If \code{TRUE}, will shrink scales to fit output of 46 | statistics, not raw data. If \code{FALSE}, will be range of raw data 47 | before statistical summary.} 48 | 49 | \item{labeller}{A function that takes one data frame of labels and 50 | returns a list or data frame of character vectors. Each input 51 | column corresponds to one factor. Thus there will be more than 52 | one with \code{vars(cyl, am)}. Each output 53 | column gets displayed as one separate line in the strip 54 | label. This function should inherit from the "labeller" S3 class 55 | for compatibility with \code{\link[ggplot2:labeller]{labeller()}}. You can use different labeling 56 | functions for different kind of labels, for example use \code{\link[ggplot2:label_parsed]{label_parsed()}} for 57 | formatting facet labels. \code{\link[ggplot2:label_value]{label_value()}} is used by default, 58 | check it for more details and pointers to other options.} 59 | 60 | \item{as.table}{If \code{TRUE}, the default, the facets are laid out like 61 | a table with highest values at the bottom-right. If \code{FALSE}, the 62 | facets are laid out like a plot with the highest value at the top-right.} 63 | 64 | \item{switch}{By default, the labels are displayed on the top and 65 | right of the plot. If \code{"x"}, the top labels will be 66 | displayed to the bottom. If \code{"y"}, the right-hand side 67 | labels will be displayed to the left. Can also be set to 68 | \code{"both"}.} 69 | 70 | \item{drop}{If \code{TRUE}, the default, all factor levels not used in the 71 | data will automatically be dropped. If \code{FALSE}, all factor levels 72 | will be shown, regardless of whether or not they appear in the data.} 73 | 74 | \item{ncol}{Number of columns per page} 75 | 76 | \item{nrow}{Number of rows per page} 77 | 78 | \item{page}{The page to draw} 79 | 80 | \item{byrow}{Should the pages be created row-wise or column wise} 81 | } 82 | \description{ 83 | This extension to \code{\link[ggplot2:facet_grid]{ggplot2::facet_grid()}} will allow you to split 84 | a facetted plot over multiple pages. You define a number of rows and columns 85 | per page as well as the page number to plot, and the function will 86 | automatically only plot the correct panels. Usually this will be put in a 87 | loop to render all pages one by one. 88 | } 89 | \note{ 90 | If either \code{ncol} or \code{nrow} is \code{NULL} this function will 91 | fall back to the standard \code{facet_grid} functionality. 92 | } 93 | \examples{ 94 | # Draw a small section of the grid 95 | ggplot(diamonds) + 96 | geom_point(aes(carat, price), alpha = 0.1) + 97 | facet_grid_paginate(color ~ cut:clarity, ncol = 3, nrow = 3, page = 4) 98 | } 99 | \seealso{ 100 | \code{\link[=n_pages]{n_pages()}} to compute the total number of pages in a paginated 101 | faceted plot 102 | 103 | Other ggforce facets: 104 | \code{\link{facet_stereo}()}, 105 | \code{\link{facet_wrap_paginate}()}, 106 | \code{\link{facet_zoom}()} 107 | } 108 | \concept{ggforce facets} 109 | -------------------------------------------------------------------------------- /man/facet_row.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/facet_row.R 3 | \name{facet_row} 4 | \alias{facet_row} 5 | \alias{facet_col} 6 | \title{One-dimensional facets} 7 | \usage{ 8 | facet_row( 9 | facets, 10 | scales = "fixed", 11 | space = "fixed", 12 | shrink = TRUE, 13 | labeller = "label_value", 14 | drop = TRUE, 15 | strip.position = "top" 16 | ) 17 | 18 | facet_col( 19 | facets, 20 | scales = "fixed", 21 | space = "fixed", 22 | shrink = TRUE, 23 | labeller = "label_value", 24 | drop = TRUE, 25 | strip.position = "top" 26 | ) 27 | } 28 | \arguments{ 29 | \item{facets}{A set of variables or expressions quoted by \code{\link[ggplot2:vars]{vars()}} 30 | and defining faceting groups on the rows or columns dimension. 31 | The variables can be named (the names are passed to \code{labeller}). 32 | 33 | For compatibility with the classic interface, can also be a 34 | formula or character vector. Use either a one sided formula, \code{~a + b}, 35 | or a character vector, \code{c("a", "b")}.} 36 | 37 | \item{scales}{Should scales be fixed (\code{"fixed"}, the default), 38 | free (\code{"free"}), or free in one dimension (\code{"free_x"}, 39 | \code{"free_y"})?} 40 | 41 | \item{space}{Should the size of the panels be fixed or relative to the range 42 | of the respective position scales} 43 | 44 | \item{shrink}{If \code{TRUE}, will shrink scales to fit output of 45 | statistics, not raw data. If \code{FALSE}, will be range of raw data 46 | before statistical summary.} 47 | 48 | \item{labeller}{A function that takes one data frame of labels and 49 | returns a list or data frame of character vectors. Each input 50 | column corresponds to one factor. Thus there will be more than 51 | one with \code{vars(cyl, am)}. Each output 52 | column gets displayed as one separate line in the strip 53 | label. This function should inherit from the "labeller" S3 class 54 | for compatibility with \code{\link[ggplot2:labeller]{labeller()}}. You can use different labeling 55 | functions for different kind of labels, for example use \code{\link[ggplot2:label_parsed]{label_parsed()}} for 56 | formatting facet labels. \code{\link[ggplot2:label_value]{label_value()}} is used by default, 57 | check it for more details and pointers to other options.} 58 | 59 | \item{drop}{If \code{TRUE}, the default, all factor levels not used in the 60 | data will automatically be dropped. If \code{FALSE}, all factor levels 61 | will be shown, regardless of whether or not they appear in the data.} 62 | 63 | \item{strip.position}{By default, the labels are displayed on the top of 64 | the plot. Using \code{strip.position} it is possible to place the labels on 65 | either of the four sides by setting \code{strip.position = c("top", 66 | "bottom", "left", "right")}} 67 | } 68 | \description{ 69 | These facets are one-dimensional versions of \code{\link[ggplot2:facet_wrap]{ggplot2::facet_wrap()}}, 70 | arranging the panels in either a single row or a single column. This 71 | restriction makes it possible to support a \code{space} argument as seen in 72 | \code{\link[ggplot2:facet_grid]{ggplot2::facet_grid()}} which, if set to \code{"free"} will allow the panels to be 73 | sized based on the relative range of their scales. Another way of thinking 74 | about them are one-dimensional versions of \code{\link[ggplot2:facet_grid]{ggplot2::facet_grid()}} (ie. 75 | \code{. ~ {var}} or \code{{var} ~ .}), but with the ability to position the strip at 76 | either side of the panel. However you look at it it is the best of both world 77 | if you just need one dimension. 78 | } 79 | \examples{ 80 | # Standard use 81 | ggplot(mtcars) + 82 | geom_point(aes(disp, mpg)) + 83 | facet_col(~gear) 84 | # It retains the ability to have unique scales for each panel 85 | ggplot(mtcars) + 86 | geom_point(aes(disp, mpg)) + 87 | facet_col(~gear, scales = 'free') 88 | 89 | # But can have free sizing along the stacking dimension 90 | ggplot(mtcars) + 91 | geom_point(aes(disp, mpg)) + 92 | facet_col(~gear, scales = 'free', space = 'free') 93 | 94 | # And you can position the strip where-ever you like 95 | ggplot(mtcars) + 96 | geom_point(aes(disp, mpg)) + 97 | facet_col(~gear, scales = 'free', space = 'free', strip.position = 'bottom') 98 | 99 | } 100 | -------------------------------------------------------------------------------- /man/facet_stereo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/facet_stereo.R 3 | \name{facet_stereo} 4 | \alias{facet_stereo} 5 | \title{Create a stereogram plot} 6 | \usage{ 7 | facet_stereo(IPD = 63.5, panel.size = 200, shrink = TRUE) 8 | } 9 | \arguments{ 10 | \item{IPD}{The interpupillary distance (in mm) used for calculating point 11 | displacement. The default value is an average of both genders} 12 | 13 | \item{panel.size}{The final plot size in mm. As IPD this is used to calculate 14 | point displacement. Don't take this value too literal but experiment until 15 | you get a nice effect. Lower values gives higher displacement and thus 16 | require the plots to be observed from a closer distance} 17 | 18 | \item{shrink}{If \code{TRUE}, will shrink scales to fit output of 19 | statistics, not raw data. If \code{FALSE}, will be range of raw data 20 | before statistical summary.} 21 | } 22 | \description{ 23 | This, arguably pretty useless function, lets you create plots with a sense of 24 | depth by creating two slightly different versions of the plot that 25 | corresponds to how the eyes would see it if the plot was 3 dimensional. To 26 | experience the effect look at the plots through 3D hardware such as Google 27 | Cardboard or by relaxing the eyes and focusing into the distance. The 28 | depth of a point is calculated for layers having a depth aesthetic supplied. 29 | The scaling of the depth can be controlled with \code{\link[=scale_depth]{scale_depth()}} as 30 | you would control any aesthetic. Negative values will result in features 31 | placed behind the paper plane, while positive values will result in 32 | features hovering in front of the paper. While features within each layer is 33 | sorted so those closest to you are plotted on top of those more distant, this 34 | cannot be done between layers. Thus, layers are always plotted on top of 35 | each others, even if the features in one layer lies behind features in a 36 | layer behind it. The depth experience is inaccurate and should not be used 37 | for conveying important data. Regard this more as a party-trick... 38 | } 39 | \examples{ 40 | # You'll have to accept a warning about depth being an unknown aesthetic 41 | ggplot(mtcars) + 42 | geom_point(aes(mpg, disp, depth = cyl)) + 43 | facet_stereo() 44 | } 45 | \seealso{ 46 | Other ggforce facets: 47 | \code{\link{facet_grid_paginate}()}, 48 | \code{\link{facet_wrap_paginate}()}, 49 | \code{\link{facet_zoom}()} 50 | } 51 | \concept{ggforce facets} 52 | -------------------------------------------------------------------------------- /man/facet_wrap_paginate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/facet_wrap_paginate.R 3 | \name{facet_wrap_paginate} 4 | \alias{facet_wrap_paginate} 5 | \title{Split facet_wrap over multiple plots} 6 | \usage{ 7 | facet_wrap_paginate( 8 | facets, 9 | nrow = NULL, 10 | ncol = NULL, 11 | scales = "fixed", 12 | shrink = TRUE, 13 | labeller = "label_value", 14 | as.table = TRUE, 15 | switch = deprecated(), 16 | drop = TRUE, 17 | dir = "h", 18 | strip.position = "top", 19 | page = 1 20 | ) 21 | } 22 | \arguments{ 23 | \item{facets}{A set of variables or expressions quoted by \code{\link[ggplot2:vars]{vars()}} 24 | and defining faceting groups on the rows or columns dimension. 25 | The variables can be named (the names are passed to \code{labeller}). 26 | 27 | For compatibility with the classic interface, can also be a 28 | formula or character vector. Use either a one sided formula, \code{~a + b}, 29 | or a character vector, \code{c("a", "b")}.} 30 | 31 | \item{nrow, ncol}{Number of rows and columns} 32 | 33 | \item{scales}{Should scales be fixed (\code{"fixed"}, the default), 34 | free (\code{"free"}), or free in one dimension (\code{"free_x"}, 35 | \code{"free_y"})?} 36 | 37 | \item{shrink}{If \code{TRUE}, will shrink scales to fit output of 38 | statistics, not raw data. If \code{FALSE}, will be range of raw data 39 | before statistical summary.} 40 | 41 | \item{labeller}{A function that takes one data frame of labels and 42 | returns a list or data frame of character vectors. Each input 43 | column corresponds to one factor. Thus there will be more than 44 | one with \code{vars(cyl, am)}. Each output 45 | column gets displayed as one separate line in the strip 46 | label. This function should inherit from the "labeller" S3 class 47 | for compatibility with \code{\link[ggplot2:labeller]{labeller()}}. You can use different labeling 48 | functions for different kind of labels, for example use \code{\link[ggplot2:label_parsed]{label_parsed()}} for 49 | formatting facet labels. \code{\link[ggplot2:label_value]{label_value()}} is used by default, 50 | check it for more details and pointers to other options.} 51 | 52 | \item{as.table}{If \code{TRUE}, the default, the facets are laid out like 53 | a table with highest values at the bottom-right. If \code{FALSE}, the 54 | facets are laid out like a plot with the highest value at the top-right.} 55 | 56 | \item{switch}{By default, the labels are displayed on the top and 57 | right of the plot. If \code{"x"}, the top labels will be 58 | displayed to the bottom. If \code{"y"}, the right-hand side 59 | labels will be displayed to the left. Can also be set to 60 | \code{"both"}.} 61 | 62 | \item{drop}{If \code{TRUE}, the default, all factor levels not used in the 63 | data will automatically be dropped. If \code{FALSE}, all factor levels 64 | will be shown, regardless of whether or not they appear in the data.} 65 | 66 | \item{dir}{Direction: either \code{"h"} for horizontal, the default, or \code{"v"}, 67 | for vertical.} 68 | 69 | \item{strip.position}{By default, the labels are displayed on the top of 70 | the plot. Using \code{strip.position} it is possible to place the labels on 71 | either of the four sides by setting \code{strip.position = c("top", 72 | "bottom", "left", "right")}} 73 | 74 | \item{page}{The page to draw} 75 | } 76 | \description{ 77 | This extension to \code{\link[ggplot2:facet_wrap]{ggplot2::facet_wrap()}} will allow you to split 78 | a facetted plot over multiple pages. You define a number of rows and columns 79 | per page as well as the page number to plot, and the function will 80 | automatically only plot the correct panels. Usually this will be put in a 81 | loop to render all pages one by one. 82 | } 83 | \note{ 84 | If either \code{ncol} or \code{nrow} is \code{NULL} this function will 85 | fall back to the standard \code{facet_wrap} functionality. 86 | } 87 | \examples{ 88 | ggplot(diamonds) + 89 | geom_point(aes(carat, price), alpha = 0.1) + 90 | facet_wrap_paginate(~ cut:clarity, ncol = 3, nrow = 3, page = 4) 91 | 92 | } 93 | \seealso{ 94 | \code{\link[=n_pages]{n_pages()}} to compute the total number of pages in a paginated 95 | faceted plot 96 | 97 | Other ggforce facets: 98 | \code{\link{facet_grid_paginate}()}, 99 | \code{\link{facet_stereo}()}, 100 | \code{\link{facet_zoom}()} 101 | } 102 | \concept{ggforce facets} 103 | -------------------------------------------------------------------------------- /man/facet_zoom.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/facet_zoom.R 3 | \name{facet_zoom} 4 | \alias{facet_zoom} 5 | \title{Facet data for zoom with context} 6 | \usage{ 7 | facet_zoom( 8 | x, 9 | y, 10 | xy, 11 | zoom.data, 12 | xlim = NULL, 13 | ylim = NULL, 14 | split = FALSE, 15 | horizontal = TRUE, 16 | zoom.size = 2, 17 | show.area = TRUE, 18 | shrink = TRUE 19 | ) 20 | } 21 | \arguments{ 22 | \item{x, y, xy}{An expression evaluating to a logical vector that determines 23 | the subset of data to zoom in on} 24 | 25 | \item{zoom.data}{An expression evaluating to a logical vector. If \code{TRUE} 26 | the data only shows in the zoom panels. If \code{FALSE} the data only show in 27 | the context panel. If \code{NA} the data will show in all panels.} 28 | 29 | \item{xlim, ylim}{Specific zoom ranges for each axis. If present they will 30 | override \code{x}, \code{y}, and/or \code{xy}.} 31 | 32 | \item{split}{If both \code{x} and \code{y} is given, should each axis zoom 33 | be shown separately as well? Defaults to \code{FALSE}} 34 | 35 | \item{horizontal}{If both \code{x} and \code{y} is given and 36 | \code{split = FALSE} How should the zoom panel be positioned relative to the 37 | full data panel? Defaults to \code{TRUE}} 38 | 39 | \item{zoom.size}{Sets the relative size of the zoom panel to the full data 40 | panel. The default (\code{2}) makes the zoom panel twice the size of the full 41 | data panel.} 42 | 43 | \item{show.area}{Should the zoom area be drawn below the data points on the 44 | full data panel? Defaults to \code{TRUE}.} 45 | 46 | \item{shrink}{If \code{TRUE}, will shrink scales to fit output of 47 | statistics, not raw data. If \code{FALSE}, will be range of raw data 48 | before statistical summary.} 49 | } 50 | \description{ 51 | This facetting provides the means to zoom in on a subset of the data, while 52 | keeping the view of the full dataset as a separate panel. The zoomed-in area 53 | will be indicated on the full dataset panel for reference. It is possible to 54 | zoom in on both the x and y axis at the same time. If this is done it is 55 | possible to both get each zoom separately and combined or just combined. 56 | } 57 | \examples{ 58 | # Zoom in on the versicolor species on the x-axis 59 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 60 | geom_point() + 61 | facet_zoom(x = Species == 'versicolor') 62 | 63 | # Zoom in on versicolor on both axes 64 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 65 | geom_point() + 66 | facet_zoom(xy = Species == 'versicolor') 67 | 68 | # Use different zoom criteria on each axis 69 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 70 | geom_point() + 71 | facet_zoom(x = Species != 'setosa', y = Species == 'versicolor') 72 | 73 | # Get each axis zoom separately as well 74 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 75 | geom_point() + 76 | facet_zoom(xy = Species == 'versicolor', split = TRUE) 77 | 78 | # Define the zoom area directly 79 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 80 | geom_point() + 81 | facet_zoom(xlim = c(2, 4)) 82 | 83 | # Selectively show data in the zoom panel 84 | ggplot(iris, aes(Petal.Length, Petal.Width, colour = Species)) + 85 | geom_point() + 86 | facet_zoom(x = Species == 'versicolor', zoom.data = Species == 'versicolor') 87 | } 88 | \seealso{ 89 | Other ggforce facets: 90 | \code{\link{facet_grid_paginate}()}, 91 | \code{\link{facet_stereo}()}, 92 | \code{\link{facet_wrap_paginate}()} 93 | } 94 | \concept{ggforce facets} 95 | -------------------------------------------------------------------------------- /man/figures/README-example-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/man/figures/README-example-1.png -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclearchivedarchived -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledefunctdefunct -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycledeprecateddeprecated -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecycleexperimentalexperimental -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclematuringmaturing -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclequestioningquestioning -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclestablestable -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | lifecyclelifecyclesupersededsuperseded -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/man/figures/logo.png -------------------------------------------------------------------------------- /man/gather_set_data.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/parallel_sets.R 3 | \name{gather_set_data} 4 | \alias{gather_set_data} 5 | \title{Tidy data for use with geom_parallel_sets} 6 | \usage{ 7 | gather_set_data(data, x, id_name = "id") 8 | } 9 | \arguments{ 10 | \item{data}{A tidy dataframe with some categorical columns} 11 | 12 | \item{x}{The columns to use for axes in the parallel sets diagram} 13 | 14 | \item{id_name}{The name of the column that will contain the original index of 15 | the row.} 16 | } 17 | \value{ 18 | A data.frame 19 | } 20 | \description{ 21 | This helper function makes it easy to change tidy data into a tidy(er) format 22 | that can be used by geom_parallel_sets. 23 | } 24 | \examples{ 25 | data <- reshape2::melt(Titanic) 26 | head(gather_set_data(data, 1:4)) 27 | head(gather_set_data(data, c("Class","Sex","Age","Survived"))) 28 | } 29 | -------------------------------------------------------------------------------- /man/geom_autopoint.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/autopoint.R 3 | \name{geom_autopoint} 4 | \alias{geom_autopoint} 5 | \title{A point geom specialised for scatterplot matrices} 6 | \usage{ 7 | geom_autopoint( 8 | mapping = NULL, 9 | data = NULL, 10 | stat = "identity", 11 | position = "auto", 12 | ..., 13 | na.rm = FALSE, 14 | show.legend = NA, 15 | inherit.aes = TRUE 16 | ) 17 | } 18 | \arguments{ 19 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 20 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 21 | at the top level of the plot. You must supply \code{mapping} if there is no plot 22 | mapping.} 23 | 24 | \item{data}{The data to be displayed in this layer. There are three 25 | options: 26 | 27 | If \code{NULL}, the default, the data is inherited from the plot 28 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 29 | 30 | A \code{data.frame}, or other object, will override the plot 31 | data. All objects will be fortified to produce a data frame. See 32 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 33 | 34 | A \code{function} will be called with a single argument, 35 | the plot data. The return value must be a \code{data.frame}, and 36 | will be used as the layer data. A \code{function} can be created 37 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 38 | 39 | \item{stat}{The statistical transformation to use on the data for this 40 | layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the 41 | stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than 42 | \code{"stat_count"})} 43 | 44 | \item{position}{Position adjustment, either as a string naming the adjustment 45 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 46 | position adjustment function. Use the latter if you need to change the 47 | settings of the adjustment.} 48 | 49 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 50 | often aesthetics, used to set an aesthetic to a fixed value, like 51 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 52 | to the paired geom/stat.} 53 | 54 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 55 | a warning. If \code{TRUE}, missing values are silently removed.} 56 | 57 | \item{show.legend}{logical. Should this layer be included in the legends? 58 | \code{NA}, the default, includes if any aesthetics are mapped. 59 | \code{FALSE} never includes, and \code{TRUE} always includes. 60 | It can also be a named logical vector to finely select the aesthetics to 61 | display.} 62 | 63 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 64 | rather than combining with them. This is most useful for helper functions 65 | that define both data and aesthetics and shouldn't inherit behaviour from 66 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 67 | } 68 | \description{ 69 | This geom is a specialisation of \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} with two changes. It 70 | defaults to mapping \code{x} and \code{y} to \code{.panel_x} and \code{.panel_y} respectively, 71 | and it defaults to using \code{\link[=position_auto]{position_auto()}} to jitter the points based on the 72 | combination of position scale types. 73 | } 74 | \examples{ 75 | # Continuous vs continuous: No jitter 76 | ggplot(mpg) + geom_autopoint(aes(cty, hwy)) 77 | 78 | # Continuous vs discrete: sina jitter 79 | ggplot(mpg) + geom_autopoint(aes(cty, drv)) 80 | 81 | # Discrete vs discrete: disc-jitter 82 | ggplot(mpg) + geom_autopoint(aes(fl, drv)) 83 | 84 | # Used with facet_matrix (x and y are automatically mapped) 85 | ggplot(mpg) + 86 | geom_autopoint() + 87 | facet_matrix(vars(drv:fl)) 88 | 89 | } 90 | \seealso{ 91 | \link{facet_matrix} for how to lay out scatterplot matrices and 92 | \link{position_auto} for information about the position adjustments 93 | } 94 | -------------------------------------------------------------------------------- /man/geom_circle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/circle.R 3 | \name{geom_circle} 4 | \alias{geom_circle} 5 | \alias{stat_circle} 6 | \title{Circles based on center and radius} 7 | \usage{ 8 | stat_circle( 9 | mapping = NULL, 10 | data = NULL, 11 | geom = "circle", 12 | position = "identity", 13 | n = 360, 14 | na.rm = FALSE, 15 | show.legend = NA, 16 | inherit.aes = TRUE, 17 | ... 18 | ) 19 | 20 | geom_circle( 21 | mapping = NULL, 22 | data = NULL, 23 | stat = "circle", 24 | position = "identity", 25 | n = 360, 26 | expand = 0, 27 | radius = 0, 28 | na.rm = FALSE, 29 | show.legend = NA, 30 | inherit.aes = TRUE, 31 | ... 32 | ) 33 | } 34 | \arguments{ 35 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 36 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 37 | at the top level of the plot. You must supply \code{mapping} if there is no plot 38 | mapping.} 39 | 40 | \item{data}{The data to be displayed in this layer. There are three 41 | options: 42 | 43 | If \code{NULL}, the default, the data is inherited from the plot 44 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 45 | 46 | A \code{data.frame}, or other object, will override the plot 47 | data. All objects will be fortified to produce a data frame. See 48 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 49 | 50 | A \code{function} will be called with a single argument, 51 | the plot data. The return value must be a \code{data.frame}, and 52 | will be used as the layer data. A \code{function} can be created 53 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 54 | 55 | \item{geom}{The geometric object to use to display the data, either as a 56 | \code{ggproto} \code{Geom} subclass or as a string naming the geom stripped of the 57 | \code{geom_} prefix (e.g. \code{"point"} rather than \code{"geom_point"})} 58 | 59 | \item{position}{Position adjustment, either as a string naming the adjustment 60 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 61 | position adjustment function. Use the latter if you need to change the 62 | settings of the adjustment.} 63 | 64 | \item{n}{The number of points on the generated path per full circle.} 65 | 66 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 67 | a warning. If \code{TRUE}, missing values are silently removed.} 68 | 69 | \item{show.legend}{logical. Should this layer be included in the legends? 70 | \code{NA}, the default, includes if any aesthetics are mapped. 71 | \code{FALSE} never includes, and \code{TRUE} always includes. 72 | It can also be a named logical vector to finely select the aesthetics to 73 | display.} 74 | 75 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 76 | rather than combining with them. This is most useful for helper functions 77 | that define both data and aesthetics and shouldn't inherit behaviour from 78 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 79 | 80 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 81 | often aesthetics, used to set an aesthetic to a fixed value, like 82 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 83 | to the paired geom/stat.} 84 | 85 | \item{stat}{The statistical transformation to use on the data for this 86 | layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the 87 | stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than 88 | \code{"stat_count"})} 89 | 90 | \item{expand}{A numeric or unit vector of length one, specifying the 91 | expansion amount. Negative values will result in contraction instead. If the 92 | value is given as a numeric it will be understood as a proportion of the 93 | plot area width.} 94 | 95 | \item{radius}{As \code{expand} but specifying the corner radius.} 96 | } 97 | \description{ 98 | This set of stats and geoms makes it possible to draw circles based on a 99 | center point and a radius. In contrast to using 100 | \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}}, the size of the circles are related to the 101 | coordinate system and not to a separate scale. These functions are intended 102 | for cartesian coordinate systems and will only produce a true circle if 103 | \code{\link[ggplot2:coord_fixed]{ggplot2::coord_fixed()}} is used. 104 | } 105 | \note{ 106 | If the intend is to draw a bubble chart then use 107 | \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} and map a variable to the size scale 108 | } 109 | \section{Aesthetics}{ 110 | 111 | geom_circle understand the following aesthetics (required aesthetics are in 112 | bold): 113 | \itemize{ 114 | \item \strong{x0} 115 | \item \strong{y0} 116 | \item \strong{r} 117 | \item color 118 | \item fill 119 | \item linewidth 120 | \item linetype 121 | \item alpha 122 | \item lineend 123 | } 124 | } 125 | 126 | \section{Computed variables}{ 127 | 128 | 129 | \describe{ 130 | \item{x, y}{The start coordinates for the segment} 131 | } 132 | } 133 | 134 | \examples{ 135 | # Lets make some data 136 | circles <- data.frame( 137 | x0 = rep(1:3, 3), 138 | y0 = rep(1:3, each = 3), 139 | r = seq(0.1, 1, length.out = 9) 140 | ) 141 | 142 | # Behold some circles 143 | ggplot() + 144 | geom_circle(aes(x0 = x0, y0 = y0, r = r, fill = r), data = circles) 145 | 146 | # Use coord_fixed to ensure true circularity 147 | ggplot() + 148 | geom_circle(aes(x0 = x0, y0 = y0, r = r, fill = r), data = circles) + 149 | coord_fixed() 150 | 151 | } 152 | \seealso{ 153 | \code{\link[=geom_arc_bar]{geom_arc_bar()}} for drawing arcs with fill 154 | } 155 | -------------------------------------------------------------------------------- /man/geom_ellipse.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ellipse.R 3 | \name{geom_ellipse} 4 | \alias{geom_ellipse} 5 | \alias{stat_ellip} 6 | \title{Draw (super)ellipses based on the coordinate system scale} 7 | \usage{ 8 | stat_ellip( 9 | mapping = NULL, 10 | data = NULL, 11 | geom = "circle", 12 | position = "identity", 13 | n = 360, 14 | na.rm = FALSE, 15 | show.legend = NA, 16 | inherit.aes = TRUE, 17 | ... 18 | ) 19 | 20 | geom_ellipse( 21 | mapping = NULL, 22 | data = NULL, 23 | stat = "ellip", 24 | position = "identity", 25 | n = 360, 26 | na.rm = FALSE, 27 | show.legend = NA, 28 | inherit.aes = TRUE, 29 | ... 30 | ) 31 | } 32 | \arguments{ 33 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 34 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 35 | at the top level of the plot. You must supply \code{mapping} if there is no plot 36 | mapping.} 37 | 38 | \item{data}{The data to be displayed in this layer. There are three 39 | options: 40 | 41 | If \code{NULL}, the default, the data is inherited from the plot 42 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 43 | 44 | A \code{data.frame}, or other object, will override the plot 45 | data. All objects will be fortified to produce a data frame. See 46 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 47 | 48 | A \code{function} will be called with a single argument, 49 | the plot data. The return value must be a \code{data.frame}, and 50 | will be used as the layer data. A \code{function} can be created 51 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 52 | 53 | \item{geom}{The geometric object to use to display the data, either as a 54 | \code{ggproto} \code{Geom} subclass or as a string naming the geom stripped of the 55 | \code{geom_} prefix (e.g. \code{"point"} rather than \code{"geom_point"})} 56 | 57 | \item{position}{Position adjustment, either as a string naming the adjustment 58 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 59 | position adjustment function. Use the latter if you need to change the 60 | settings of the adjustment.} 61 | 62 | \item{n}{The number of points to sample along the ellipse.} 63 | 64 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 65 | a warning. If \code{TRUE}, missing values are silently removed.} 66 | 67 | \item{show.legend}{logical. Should this layer be included in the legends? 68 | \code{NA}, the default, includes if any aesthetics are mapped. 69 | \code{FALSE} never includes, and \code{TRUE} always includes. 70 | It can also be a named logical vector to finely select the aesthetics to 71 | display.} 72 | 73 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 74 | rather than combining with them. This is most useful for helper functions 75 | that define both data and aesthetics and shouldn't inherit behaviour from 76 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 77 | 78 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 79 | often aesthetics, used to set an aesthetic to a fixed value, like 80 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 81 | to the paired geom/stat.} 82 | 83 | \item{stat}{The statistical transformation to use on the data for this 84 | layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the 85 | stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than 86 | \code{"stat_count"})} 87 | } 88 | \description{ 89 | This is a generalisation of \code{\link[=geom_circle]{geom_circle()}} that allows you to draw 90 | ellipses at a specified angle and center relative to the coordinate system. 91 | Apart from letting you draw regular ellipsis, the stat is using the 92 | generalised formula for superellipses which can be utilised by setting the 93 | \code{m1} and \code{m2} aesthetics. If you only set the m1 the m2 value will follow 94 | that to ensure a symmetric appearance. 95 | } 96 | \section{Aesthetics}{ 97 | 98 | geom_arc understand the following aesthetics (required aesthetics are in 99 | bold): 100 | \itemize{ 101 | \item \strong{x0} 102 | \item \strong{y0} 103 | \item \strong{a} 104 | \item \strong{b} 105 | \item \strong{angle} 106 | \item m1 107 | \item m2 108 | \item color 109 | \item fill 110 | \item linewidth 111 | \item linetype 112 | \item alpha 113 | \item lineend 114 | } 115 | } 116 | 117 | \section{Computed variables}{ 118 | 119 | 120 | \describe{ 121 | \item{x, y}{The coordinates for the points along the ellipse} 122 | } 123 | } 124 | 125 | \examples{ 126 | # Basic usage 127 | ggplot() + 128 | geom_ellipse(aes(x0 = 0, y0 = 0, a = 10, b = 3, angle = 0)) + 129 | coord_fixed() 130 | 131 | # Rotation 132 | # Note that it expects radians and rotates the ellipse counter-clockwise 133 | ggplot() + 134 | geom_ellipse(aes(x0 = 0, y0 = 0, a = 10, b = 3, angle = pi / 4)) + 135 | coord_fixed() 136 | 137 | # Draw a super ellipse 138 | ggplot() + 139 | geom_ellipse(aes(x0 = 0, y0 = 0, a = 6, b = 3, angle = -pi / 3, m1 = 3)) + 140 | coord_fixed() 141 | } 142 | -------------------------------------------------------------------------------- /man/geom_regon.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/regon.R 3 | \name{geom_regon} 4 | \alias{geom_regon} 5 | \alias{stat_regon} 6 | \title{Draw regular polygons by specifying number of sides} 7 | \usage{ 8 | stat_regon( 9 | mapping = NULL, 10 | data = NULL, 11 | geom = "shape", 12 | position = "identity", 13 | na.rm = FALSE, 14 | show.legend = NA, 15 | inherit.aes = TRUE, 16 | ... 17 | ) 18 | 19 | geom_regon( 20 | mapping = NULL, 21 | data = NULL, 22 | stat = "regon", 23 | position = "identity", 24 | na.rm = FALSE, 25 | show.legend = NA, 26 | inherit.aes = TRUE, 27 | ... 28 | ) 29 | } 30 | \arguments{ 31 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 32 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 33 | at the top level of the plot. You must supply \code{mapping} if there is no plot 34 | mapping.} 35 | 36 | \item{data}{The data to be displayed in this layer. There are three 37 | options: 38 | 39 | If \code{NULL}, the default, the data is inherited from the plot 40 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 41 | 42 | A \code{data.frame}, or other object, will override the plot 43 | data. All objects will be fortified to produce a data frame. See 44 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 45 | 46 | A \code{function} will be called with a single argument, 47 | the plot data. The return value must be a \code{data.frame}, and 48 | will be used as the layer data. A \code{function} can be created 49 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 50 | 51 | \item{geom}{The geometric object to use to display the data, either as a 52 | \code{ggproto} \code{Geom} subclass or as a string naming the geom stripped of the 53 | \code{geom_} prefix (e.g. \code{"point"} rather than \code{"geom_point"})} 54 | 55 | \item{position}{Position adjustment, either as a string naming the adjustment 56 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 57 | position adjustment function. Use the latter if you need to change the 58 | settings of the adjustment.} 59 | 60 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 61 | a warning. If \code{TRUE}, missing values are silently removed.} 62 | 63 | \item{show.legend}{logical. Should this layer be included in the legends? 64 | \code{NA}, the default, includes if any aesthetics are mapped. 65 | \code{FALSE} never includes, and \code{TRUE} always includes. 66 | It can also be a named logical vector to finely select the aesthetics to 67 | display.} 68 | 69 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 70 | rather than combining with them. This is most useful for helper functions 71 | that define both data and aesthetics and shouldn't inherit behaviour from 72 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 73 | 74 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 75 | often aesthetics, used to set an aesthetic to a fixed value, like 76 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 77 | to the paired geom/stat.} 78 | 79 | \item{stat}{The statistical transformation to use on the data for this 80 | layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the 81 | stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than 82 | \code{"stat_count"})} 83 | } 84 | \description{ 85 | This geom makes it easy to construct regular polygons (polygons where all 86 | sides and angles are equal) by specifying the number of sides, position, and 87 | size. The polygons are always rotated so that they "rest" on a flat side, but 88 | this can be changed with the angle aesthetic. The size is based on the radius 89 | of their circumcircle and is thus not proportional to their area. 90 | } 91 | \section{Aesthetics}{ 92 | 93 | geom_regon understand the following aesthetics (required aesthetics are in 94 | bold): 95 | \itemize{ 96 | \item \strong{x0} x coordinate 97 | \item \strong{y0} y coordinate 98 | \item \strong{sides} the number of sides for regon 99 | \item \strong{r} the ratio of regon with respect to plot 100 | \item \strong{angle} regon rotation angle (unit is radian) 101 | \item color 102 | \item fill 103 | \item size 104 | \item linetype 105 | \item alpha 106 | \item lineend 107 | } 108 | } 109 | 110 | \section{Computed variables}{ 111 | 112 | 113 | \describe{ 114 | \item{x, y}{The coordinates for the corners of the polygon} 115 | } 116 | } 117 | 118 | \examples{ 119 | ggplot() + 120 | geom_regon(aes(x0 = runif(8), y0 = runif(8), sides = sample(3:10, 8), 121 | angle = 0, r = runif(8) / 10)) + 122 | coord_fixed() 123 | 124 | # The polygons are drawn with geom_shape, so can be manipulated as such 125 | ggplot() + 126 | geom_regon(aes(x0 = runif(8), y0 = runif(8), sides = sample(3:10, 8), 127 | angle = 0, r = runif(8) / 10), 128 | expand = unit(1, 'cm'), radius = unit(1, 'cm')) + 129 | coord_fixed() 130 | } 131 | -------------------------------------------------------------------------------- /man/geom_shape.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/shape.R 3 | \name{geom_shape} 4 | \alias{geom_shape} 5 | \title{Draw polygons with expansion/contraction and/or rounded corners} 6 | \usage{ 7 | geom_shape( 8 | mapping = NULL, 9 | data = NULL, 10 | stat = "identity", 11 | position = "identity", 12 | expand = 0, 13 | radius = 0, 14 | ..., 15 | na.rm = FALSE, 16 | show.legend = NA, 17 | inherit.aes = TRUE 18 | ) 19 | } 20 | \arguments{ 21 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 22 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 23 | at the top level of the plot. You must supply \code{mapping} if there is no plot 24 | mapping.} 25 | 26 | \item{data}{The data to be displayed in this layer. There are three 27 | options: 28 | 29 | If \code{NULL}, the default, the data is inherited from the plot 30 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 31 | 32 | A \code{data.frame}, or other object, will override the plot 33 | data. All objects will be fortified to produce a data frame. See 34 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 35 | 36 | A \code{function} will be called with a single argument, 37 | the plot data. The return value must be a \code{data.frame}, and 38 | will be used as the layer data. A \code{function} can be created 39 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 40 | 41 | \item{stat}{The statistical transformation to use on the data for this 42 | layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the 43 | stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than 44 | \code{"stat_count"})} 45 | 46 | \item{position}{Position adjustment, either as a string naming the adjustment 47 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 48 | position adjustment function. Use the latter if you need to change the 49 | settings of the adjustment.} 50 | 51 | \item{expand}{A numeric or unit vector of length one, specifying the 52 | expansion amount. Negative values will result in contraction instead. If the 53 | value is given as a numeric it will be understood as a proportion of the 54 | plot area width.} 55 | 56 | \item{radius}{As \code{expand} but specifying the corner radius.} 57 | 58 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 59 | often aesthetics, used to set an aesthetic to a fixed value, like 60 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 61 | to the paired geom/stat.} 62 | 63 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 64 | a warning. If \code{TRUE}, missing values are silently removed.} 65 | 66 | \item{show.legend}{logical. Should this layer be included in the legends? 67 | \code{NA}, the default, includes if any aesthetics are mapped. 68 | \code{FALSE} never includes, and \code{TRUE} always includes. 69 | It can also be a named logical vector to finely select the aesthetics to 70 | display.} 71 | 72 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 73 | rather than combining with them. This is most useful for helper functions 74 | that define both data and aesthetics and shouldn't inherit behaviour from 75 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 76 | } 77 | \description{ 78 | This geom is a cousin of \code{\link[ggplot2:geom_polygon]{ggplot2::geom_polygon()}} with the added 79 | possibility of expanding or contracting the polygon by an absolute amount 80 | (e.g. 1 cm). Furthermore, it is possible to round the corners of the polygon, 81 | again by an absolute amount. The resulting geom reacts to resizing of the 82 | plot, so the expansion/contraction and corner radius will not get distorted. 83 | If no expansion/contraction or corner radius is specified, the geom falls 84 | back to \code{geom_polygon} so there is no performance penality in using this 85 | instead of \code{geom_polygon}. 86 | } 87 | \note{ 88 | Some settings can result in the dissappearance of polygons, 89 | specifically when contracting or rounding corners with a relatively large 90 | amount. Also note that x and y scale limits does not take expansion into 91 | account and the resulting polygon might thus not fit into the plot. 92 | } 93 | \section{Aesthetics}{ 94 | 95 | geom_shape understand the following aesthetics (required aesthetics are in 96 | bold): 97 | \itemize{ 98 | \item \strong{x} 99 | \item \strong{y} 100 | \item color 101 | \item fill 102 | \item group 103 | \item size 104 | \item linetype 105 | \item alpha 106 | } 107 | } 108 | 109 | \examples{ 110 | shape <- data.frame( 111 | x = c(0.5, 1, 0.75, 0.25, 0), 112 | y = c(0, 0.5, 1, 0.75, 0.25) 113 | ) 114 | # Expand and round 115 | ggplot(shape, aes(x = x, y = y)) + 116 | geom_shape(expand = unit(1, 'cm'), radius = unit(0.5, 'cm')) + 117 | geom_polygon(fill = 'red') 118 | 119 | # Contract 120 | ggplot(shape, aes(x = x, y = y)) + 121 | geom_polygon(fill = 'red') + 122 | geom_shape(expand = unit(-1, 'cm')) 123 | 124 | # Only round corners 125 | ggplot(shape, aes(x = x, y = y)) + 126 | geom_polygon(fill = 'red') + 127 | geom_shape(radius = unit(1, 'cm')) 128 | } 129 | \author{ 130 | Thomas Lin Pedersen 131 | } 132 | -------------------------------------------------------------------------------- /man/geom_spiro.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/spiro.R 3 | \name{geom_spiro} 4 | \alias{geom_spiro} 5 | \alias{stat_spiro} 6 | \title{Draw spirograms based on the radii of the different "wheels" involved} 7 | \usage{ 8 | stat_spiro( 9 | mapping = NULL, 10 | data = NULL, 11 | geom = "path", 12 | position = "identity", 13 | na.rm = FALSE, 14 | n = 500, 15 | revolutions = NULL, 16 | show.legend = NA, 17 | inherit.aes = TRUE, 18 | ... 19 | ) 20 | 21 | geom_spiro( 22 | mapping = NULL, 23 | data = NULL, 24 | stat = "spiro", 25 | position = "identity", 26 | arrow = NULL, 27 | n = 500, 28 | lineend = "butt", 29 | na.rm = FALSE, 30 | show.legend = NA, 31 | inherit.aes = TRUE, 32 | ... 33 | ) 34 | } 35 | \arguments{ 36 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 37 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 38 | at the top level of the plot. You must supply \code{mapping} if there is no plot 39 | mapping.} 40 | 41 | \item{data}{The data to be displayed in this layer. There are three 42 | options: 43 | 44 | If \code{NULL}, the default, the data is inherited from the plot 45 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 46 | 47 | A \code{data.frame}, or other object, will override the plot 48 | data. All objects will be fortified to produce a data frame. See 49 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 50 | 51 | A \code{function} will be called with a single argument, 52 | the plot data. The return value must be a \code{data.frame}, and 53 | will be used as the layer data. A \code{function} can be created 54 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 55 | 56 | \item{geom}{The geometric object to use to display the data, either as a 57 | \code{ggproto} \code{Geom} subclass or as a string naming the geom stripped of the 58 | \code{geom_} prefix (e.g. \code{"point"} rather than \code{"geom_point"})} 59 | 60 | \item{position}{Position adjustment, either as a string naming the adjustment 61 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 62 | position adjustment function. Use the latter if you need to change the 63 | settings of the adjustment.} 64 | 65 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 66 | a warning. If \code{TRUE}, missing values are silently removed.} 67 | 68 | \item{n}{The number of points that should be used to draw a fully closed 69 | spirogram. If \code{revolutions < 1} the actual number of points will be less 70 | than this.} 71 | 72 | \item{revolutions}{The number of times the inner gear should revolve around 73 | inside the outer gear. If \code{NULL} the number of revolutions to reach the 74 | starting position is calculated and used.} 75 | 76 | \item{show.legend}{logical. Should this layer be included in the legends? 77 | \code{NA}, the default, includes if any aesthetics are mapped. 78 | \code{FALSE} never includes, and \code{TRUE} always includes. 79 | It can also be a named logical vector to finely select the aesthetics to 80 | display.} 81 | 82 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 83 | rather than combining with them. This is most useful for helper functions 84 | that define both data and aesthetics and shouldn't inherit behaviour from 85 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 86 | 87 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 88 | often aesthetics, used to set an aesthetic to a fixed value, like 89 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 90 | to the paired geom/stat.} 91 | 92 | \item{stat}{The statistical transformation to use on the data for this 93 | layer, either as a \code{ggproto} \code{Geom} subclass or as a string naming the 94 | stat stripped of the \code{stat_} prefix (e.g. \code{"count"} rather than 95 | \code{"stat_count"})} 96 | 97 | \item{arrow}{Arrow specification, as created by \code{\link[grid:arrow]{grid::arrow()}}.} 98 | 99 | \item{lineend}{Line end style (round, butt, square).} 100 | } 101 | \description{ 102 | This, rather pointless, geom allows you to draw spirograms, as known from the 103 | popular drawing toy where lines were traced by inserting a pencil into a hole 104 | in a small gear that would then trace around inside another gear. The 105 | potential practicality of this geom is slim and it excists mainly for fun and 106 | art. 107 | } 108 | \section{Aesthetics}{ 109 | 110 | stat_spiro and geom_spiro understand the following aesthetics (required 111 | aesthetics are in bold): 112 | \itemize{ 113 | \item \strong{R} 114 | \item \strong{r} 115 | \item \strong{d} 116 | \item x0 117 | \item y0 118 | \item outer 119 | \item color 120 | \item size 121 | \item linetype 122 | \item alpha 123 | } 124 | } 125 | 126 | \section{Computed variables}{ 127 | 128 | 129 | \describe{ 130 | \item{x, y}{The coordinates for the path describing the spirogram} 131 | \item{index}{The progression along the spirogram mapped between 0 and 1} 132 | } 133 | } 134 | 135 | \examples{ 136 | # Basic usage 137 | ggplot() + 138 | geom_spiro(aes(R = 10, r = 3, d = 5)) 139 | 140 | # Only draw a portion 141 | ggplot() + 142 | geom_spiro(aes(R = 10, r = 3, d = 5), revolutions = 1.2) 143 | 144 | # Let the inner gear circle the outside of the outer gear 145 | ggplot() + 146 | geom_spiro(aes(R = 10, r = 3, d = 5, outer = TRUE)) 147 | } 148 | -------------------------------------------------------------------------------- /man/ggforce-extensions.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/shape.R, R/arc_bar.R, R/arc.R, R/autodensity.R, 3 | % R/autohistogram.R, R/bezier.R, R/bspline.R, R/bspline_closed.R, 4 | % R/circle.R, R/diagonal.R, R/diagonal_wide.R, R/ellipse.R, R/errorbar.R, 5 | % R/facet_grid_paginate.R, R/facet_matrix.R, R/facet_row.R, R/facet_stereo.R, 6 | % R/facet_wrap_paginate.R, R/facet_zoom.R, R/ggproto-classes.R, 7 | % R/interpolate.R, R/link.R, R/mark_circle.R, R/mark_ellipse.R, 8 | % R/mark_hull.R, R/mark_rect.R, R/parallel_sets.R, R/position-jitternormal.R, 9 | % R/position_auto.R, R/position_floatstack.R, R/regon.R, R/sina.R, R/spiro.R, 10 | % R/voronoi.R 11 | \docType{data} 12 | \name{GeomShape} 13 | \alias{GeomShape} 14 | \alias{StatArcBar} 15 | \alias{StatPie} 16 | \alias{GeomArcBar} 17 | \alias{StatArc} 18 | \alias{GeomArc} 19 | \alias{StatArc2} 20 | \alias{StatArc0} 21 | \alias{GeomArc0} 22 | \alias{StatAutodensity} 23 | \alias{GeomAutoarea} 24 | \alias{StatAutobin} 25 | \alias{GeomAutorect} 26 | \alias{StatBezier} 27 | \alias{StatBezier2} 28 | \alias{StatBezier0} 29 | \alias{GeomBezier0} 30 | \alias{StatBspline} 31 | \alias{StatBspline2} 32 | \alias{GeomBspline0} 33 | \alias{GeomBsplineClosed0} 34 | \alias{StatCircle} 35 | \alias{GeomCircle} 36 | \alias{StatDiagonal} 37 | \alias{StatDiagonal2} 38 | \alias{StatDiagonal0} 39 | \alias{StatDiagonalWide} 40 | \alias{StatEllip} 41 | \alias{StatErr} 42 | \alias{FacetGridPaginate} 43 | \alias{FacetMatrix} 44 | \alias{FacetRow} 45 | \alias{FacetCol} 46 | \alias{FacetStereo} 47 | \alias{FacetWrapPaginate} 48 | \alias{FacetZoom} 49 | \alias{ggforce-extensions} 50 | \alias{GeomPathInterpolate} 51 | \alias{StatLink} 52 | \alias{StatLink2} 53 | \alias{GeomMarkCircle} 54 | \alias{GeomMarkEllipse} 55 | \alias{GeomMarkHull} 56 | \alias{GeomMarkRect} 57 | \alias{StatParallelSets} 58 | \alias{StatParallelSetsAxes} 59 | \alias{GeomParallelSetsAxes} 60 | \alias{PositionJitterNormal} 61 | \alias{PositionAuto} 62 | \alias{PositionFloatstack} 63 | \alias{StatRegon} 64 | \alias{StatSina} 65 | \alias{StatSpiro} 66 | \alias{StatVoronoiTile} 67 | \alias{StatVoronoiSegment} 68 | \alias{StatDelaunayTile} 69 | \alias{StatDelaunaySegment} 70 | \alias{StatDelaunaySegment2} 71 | \alias{StatDelvorSummary} 72 | \title{ggforce extensions to ggplot2} 73 | \description{ 74 | ggforce makes heavy use of the ggproto class system to extend the 75 | functionality of ggplot2. In general the actual classes should be of little 76 | interest to users as the standard ggplot2 api of using geom_* and stat_* 77 | functions for building up the plot is encouraged. 78 | } 79 | \keyword{datasets} 80 | -------------------------------------------------------------------------------- /man/ggforce-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ggforce-package.R 3 | \docType{package} 4 | \name{ggforce-package} 5 | \alias{ggforce} 6 | \alias{ggforce-package} 7 | \title{ggforce: Accelerating 'ggplot2'} 8 | \description{ 9 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 10 | 11 | The aim of 'ggplot2' is to aid in visual data investigations. This focus has led to a lack of facilities for composing specialised plots. 'ggforce' aims to be a collection of mainly new stats and geoms that fills this gap. All additional functionality is aimed to come through the official extension system so using 'ggforce' should be a stable experience. 12 | } 13 | \examples{ 14 | rocketData <- data.frame( 15 | x = c(1, 1, 2, 2), 16 | y = c(1, 2, 2, 3) 17 | ) 18 | rocketData <- do.call(rbind, lapply(seq_len(500) - 1, function(i) { 19 | rocketData$y <- rocketData$y - c(0, i / 500) 20 | rocketData$group <- i + 1 21 | rocketData 22 | })) 23 | rocketData2 <- data.frame( 24 | x = c(2, 2.25, 2), 25 | y = c(2, 2.5, 3) 26 | ) 27 | rocketData2 <- do.call(rbind, lapply(seq_len(500) - 1, function(i) { 28 | rocketData2$x[2] <- rocketData2$x[2] - i * 0.25 / 500 29 | rocketData2$group <- i + 1 + 500 30 | rocketData2 31 | })) 32 | 33 | ggplot() + geom_link(aes( 34 | x = 2, y = 2, xend = 3, yend = 3, alpha = after_stat(index), 35 | size = after_stat(index) 36 | ), colour = 'goldenrod', n = 500) + 37 | geom_bezier(aes(x = x, y = y, group = group, colour = after_stat(index)), 38 | data = rocketData 39 | ) + 40 | geom_bezier(aes(x = y, y = x, group = group, colour = after_stat(index)), 41 | data = rocketData 42 | ) + 43 | geom_bezier(aes(x = x, y = y, group = group, colour = 1), 44 | data = rocketData2 45 | ) + 46 | geom_bezier(aes(x = y, y = x, group = group, colour = 1), 47 | data = rocketData2 48 | ) + 49 | geom_text(aes(x = 1.65, y = 1.65, label = 'ggplot2', angle = 45), 50 | colour = 'white', size = 15 51 | ) + 52 | coord_fixed() + 53 | scale_x_reverse() + 54 | scale_y_reverse() + 55 | scale_alpha(range = c(1, 0), guide = 'none') + 56 | scale_size_continuous( 57 | range = c(20, 0.1), trans = 'exp', 58 | guide = 'none' 59 | ) + 60 | scale_color_continuous(guide = 'none') + 61 | xlab('') + ylab('') + 62 | ggtitle('ggforce: Accelerating ggplot2') + 63 | theme(plot.title = element_text(size = 20)) 64 | } 65 | \seealso{ 66 | Useful links: 67 | \itemize{ 68 | \item \url{https://ggforce.data-imaginist.com} 69 | \item \url{https://github.com/thomasp85/ggforce} 70 | \item Report bugs at \url{https://github.com/thomasp85/ggforce/issues} 71 | } 72 | 73 | } 74 | \author{ 75 | \strong{Maintainer}: Thomas Lin Pedersen \email{thomasp85@gmail.com} (\href{https://orcid.org/0000-0002-5147-4711}{ORCID}) 76 | 77 | Other contributors: 78 | \itemize{ 79 | \item RStudio [copyright holder] 80 | } 81 | 82 | } 83 | \keyword{internal} 84 | -------------------------------------------------------------------------------- /man/interpolateDataFrame.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/interpolate.R 3 | \name{interpolateDataFrame} 4 | \alias{interpolateDataFrame} 5 | \title{Interpolate layer data} 6 | \usage{ 7 | interpolateDataFrame(data) 8 | } 9 | \arguments{ 10 | \item{data}{A data.frame with data for a layer} 11 | } 12 | \value{ 13 | A similar data.frame with NA values interpolated 14 | } 15 | \description{ 16 | Interpolate layer data 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/label_tex.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/labeller.R 3 | \name{label_tex} 4 | \alias{label_tex} 5 | \title{A labeller function to parse TeX syntax} 6 | \usage{ 7 | label_tex(labels, ...) 8 | } 9 | \arguments{ 10 | \item{labels}{Data frame of labels. Usually contains only one 11 | element, but faceting over multiple factors entails multiple 12 | label variables.} 13 | 14 | \item{...}{ 15 | Arguments passed on to \code{\link[ggplot2:labellers]{ggplot2::label_parsed}} 16 | \describe{ 17 | \item{\code{multi_line}}{Whether to display the labels of multiple factors 18 | on separate lines.} 19 | }} 20 | } 21 | \description{ 22 | This function formats the strip labels of facet grids and wraps that contains 23 | TeX expressions. The latex2exp package must be installed. 24 | } 25 | \examples{ 26 | # requires latex2exp package be installed 27 | if (requireNamespace("latex2exp", quietly = TRUE)) { 28 | library(ggplot2) 29 | d <- data.frame(x = 1, y = 1, facet = "$\\\\beta$") 30 | ggplot(d, aes(x, y)) + 31 | geom_point() + 32 | facet_wrap(~ facet, labeller = label_tex) 33 | } 34 | } 35 | \seealso{ 36 | \link[ggplot2:labeller]{ggplot2::labeller}, \code{\link[latex2exp:TeX]{latex2exp::TeX()}} 37 | } 38 | -------------------------------------------------------------------------------- /man/linear_trans.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trans_linear.R 3 | \name{linear_trans} 4 | \alias{linear_trans} 5 | \alias{rotate} 6 | \alias{stretch} 7 | \alias{shear} 8 | \alias{translate} 9 | \alias{reflect} 10 | \title{Create a custom linear transformation} 11 | \usage{ 12 | linear_trans(...) 13 | 14 | rotate(angle) 15 | 16 | stretch(x, y) 17 | 18 | shear(x, y) 19 | 20 | translate(x, y) 21 | 22 | reflect(x, y) 23 | } 24 | \arguments{ 25 | \item{...}{A number of transformation functions.} 26 | 27 | \item{angle}{An angle in radians} 28 | 29 | \item{x}{the transformation magnitude in the x-direction} 30 | 31 | \item{y}{the transformation magnitude in the x-direction} 32 | } 33 | \value{ 34 | \code{linear_trans} creates a trans object. The other functions 35 | return a 3x3 transformation matrix. 36 | } 37 | \description{ 38 | This function lets you compose transformations based on a sequence of linear 39 | transformations. If the transformations are parameterised the parameters will 40 | become arguments in the transformation function. The transformations are 41 | one of \code{rotate}, \code{shear}, \code{stretch}, \code{translate}, and 42 | \code{reflect}. 43 | } 44 | \examples{ 45 | trans <- linear_trans(rotate(a), shear(1, 0), translate(x1, y1)) 46 | square <- data.frame(x = c(0, 0, 1, 1), y = c(0, 1, 1, 0)) 47 | square2 <- trans$transform(square$x, square$y, a = pi / 3, x1 = 4, y1 = 8) 48 | square3 <- trans$transform(square$x, square$y, a = pi / 1.5, x1 = 2, y1 = -6) 49 | square <- rbind(square, square2, square3) 50 | square$group <- rep(1:3, each = 4) 51 | ggplot(square, aes(x, y, group = group)) + 52 | geom_polygon(aes(fill = factor(group)), colour = 'black') 53 | } 54 | -------------------------------------------------------------------------------- /man/n_pages.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/facet_wrap_paginate.R 3 | \name{n_pages} 4 | \alias{n_pages} 5 | \title{Determine the number of pages in a paginated facet plot} 6 | \usage{ 7 | n_pages(plot) 8 | } 9 | \arguments{ 10 | \item{plot}{A ggplot object using either facet_wrap_paginate or 11 | facet_grid_paginate} 12 | } 13 | \value{ 14 | If the plot uses using either facet_wrap_paginate or 15 | facet_grid_paginate it returns the total number of pages. Otherwise it 16 | returns NULL 17 | } 18 | \description{ 19 | This is a simple helper that returns the number of pages it takes to plot all 20 | panels when using \code{\link[=facet_wrap_paginate]{facet_wrap_paginate()}} and 21 | \code{\link[=facet_grid_paginate]{facet_grid_paginate()}}. It partially builds the plot so depending 22 | on the complexity of your plot it might take some time to calculate... 23 | } 24 | \examples{ 25 | p <- ggplot(diamonds) + 26 | geom_point(aes(carat, price), alpha = 0.1) + 27 | facet_wrap_paginate(~ cut:clarity, ncol = 3, nrow = 3, page = 1) 28 | n_pages(p) 29 | } 30 | -------------------------------------------------------------------------------- /man/position_auto.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/position_auto.R 3 | \name{position_auto} 4 | \alias{position_auto} 5 | \title{Jitter based on scale types} 6 | \usage{ 7 | position_auto(jitter.width = 0.75, bw = "nrd0", scale = TRUE, seed = NA) 8 | } 9 | \arguments{ 10 | \item{jitter.width}{The maximal width of the jitter} 11 | 12 | \item{bw}{The smoothing bandwidth to use in the case of sina jittering. See 13 | the \code{bw} argument in \link[stats:density]{stats::density}} 14 | 15 | \item{scale}{Should the width of jittering be scaled based on the number of 16 | points in the group} 17 | 18 | \item{seed}{A seed to supply to make the jittering reproducible across layers} 19 | } 20 | \description{ 21 | This position adjustment is able to select a meaningful jitter of the data 22 | based on the combination of positional scale types. IT behaves differently 23 | depending on if none, one, or both the x and y scales are discrete. If both 24 | are discrete it will jitter the datapoints evenly inside a disc, if one of 25 | them is discrete it will jitter the discrete dimension to follow the density 26 | along the other dimension (like a sina plot). If neither are discrete it will 27 | not do any jittering. 28 | } 29 | \examples{ 30 | # Continuous vs continuous: No jitter 31 | ggplot(mpg) + geom_point(aes(cty, hwy), position = 'auto') 32 | 33 | # Continuous vs discrete: sina jitter 34 | ggplot(mpg) + geom_point(aes(cty, drv), position = 'auto') 35 | 36 | # Discrete vs discrete: disc-jitter 37 | ggplot(mpg) + geom_point(aes(fl, drv), position = 'auto') 38 | 39 | # Don't scale the jitter based on group size 40 | ggplot(mpg) + geom_point(aes(cty, drv), position = position_auto(scale = FALSE)) 41 | ggplot(mpg) + geom_point(aes(fl, drv), position = position_auto(scale = FALSE)) 42 | 43 | } 44 | \seealso{ 45 | \link{geom_autopoint} for a point geom that uses auto-position by default 46 | } 47 | -------------------------------------------------------------------------------- /man/position_jitternormal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/position-jitternormal.R 3 | \name{position_jitternormal} 4 | \alias{position_jitternormal} 5 | \title{Jitter points with normally distributed random noise} 6 | \usage{ 7 | position_jitternormal(sd_x = NULL, sd_y = NULL, seed = NA) 8 | } 9 | \arguments{ 10 | \item{sd_x, sd_y}{Standard deviation to add along the x and y axes. The 11 | function uses \code{\link[stats:Normal]{stats::rnorm()}} with \code{mean = 0} behind the scenes. 12 | 13 | If omitted, defaults to 0.15. As with \code{\link[ggplot2:geom_jitter]{ggplot2::geom_jitter()}}, categorical 14 | data is aligned on the integers, so a standard deviation of more than 0.2 15 | will spread the data so it's not possible to see the distinction between 16 | the categories.} 17 | 18 | \item{seed}{A random seed to make the jitter reproducible. 19 | Useful if you need to apply the same jitter twice, e.g., for a point and 20 | a corresponding label. 21 | The random seed is reset after jittering. 22 | If \code{NA} (the default value), the seed is initialised with a random value; 23 | this makes sure that two subsequent calls start with a different seed. 24 | Use \code{NULL} to use the current random seed and also avoid resetting 25 | (the behaviour of \pkg{ggplot} 2.2.1 and earlier).} 26 | } 27 | \description{ 28 | \code{\link[ggplot2:geom_jitter]{ggplot2::geom_jitter()}} adds random noise to points using a uniform 29 | distribution. When many points are plotted, they appear in a rectangle. This 30 | position jitters points using a normal distribution instead, resulting in 31 | more circular clusters. 32 | } 33 | \examples{ 34 | # Example data 35 | df <- data.frame( 36 | x = sample(1:3, 1500, TRUE), 37 | y = sample(1:3, 1500, TRUE) 38 | ) 39 | 40 | # position_jitter results in rectangular clusters 41 | ggplot(df, aes(x = x, y = y)) + 42 | geom_point(position = position_jitter()) 43 | 44 | # geom_jitternormal results in more circular clusters 45 | ggplot(df, aes(x = x, y = y)) + 46 | geom_point(position = position_jitternormal()) 47 | 48 | # You can adjust the standard deviations along both axes 49 | # Tighter circles 50 | ggplot(df, aes(x = x, y = y)) + 51 | geom_point(position = position_jitternormal(sd_x = 0.08, sd_y = 0.08)) 52 | 53 | # Oblong shapes 54 | ggplot(df, aes(x = x, y = y)) + 55 | geom_point(position = position_jitternormal(sd_x = 0.2, sd_y = 0.08)) 56 | 57 | # Only add random noise to one dimension 58 | ggplot(df, aes(x = x, y = y)) + 59 | geom_point( 60 | position = position_jitternormal(sd_x = 0.15, sd_y = 0), 61 | alpha = 0.1 62 | ) 63 | } 64 | \concept{position adjustments} 65 | -------------------------------------------------------------------------------- /man/power_trans.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trans.R 3 | \name{power_trans} 4 | \alias{power_trans} 5 | \title{Create a power transformation object} 6 | \usage{ 7 | power_trans(n) 8 | } 9 | \arguments{ 10 | \item{n}{The degree of the power transformation} 11 | } 12 | \value{ 13 | A trans object 14 | } 15 | \description{ 16 | This function can be used to create a proper trans object that encapsulates 17 | a power transformation (x^n). 18 | } 19 | \examples{ 20 | # Power of 2 transformations 21 | trans <- power_trans(2) 22 | trans$transform(1:10) 23 | 24 | # Cubic root transformation 25 | trans <- power_trans(1 / 3) 26 | trans$transform(1:10) 27 | 28 | # Use it in a plot 29 | ggplot() + 30 | geom_line(aes(x = 1:10, y = 1:10)) + 31 | scale_x_continuous(trans = power_trans(2), 32 | expand = c(0, 1)) 33 | } 34 | -------------------------------------------------------------------------------- /man/radial_trans.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trans.R 3 | \name{radial_trans} 4 | \alias{radial_trans} 5 | \title{Create radial data in a cartesian coordinate system} 6 | \usage{ 7 | radial_trans(r.range, a.range, offset = pi/2, pad = 0.5, clip = FALSE) 8 | } 9 | \arguments{ 10 | \item{r.range}{The range in radius that correspond to 0 - 1 in the unit 11 | circle.} 12 | 13 | \item{a.range}{The range in angles that correspond to 2*pi - 0. As radians 14 | are normally measured counterclockwise while radial displays are read 15 | clockwise it's an inverse mapping} 16 | 17 | \item{offset}{The offset in angles to apply. Determines that start position 18 | on the circle. pi/2 (the default) corresponds to 12 o'clock.} 19 | 20 | \item{pad}{Adds to the end points of the angle range in order to separate the 21 | start and end point. Defaults to 0.5} 22 | 23 | \item{clip}{Should input data be clipped to r.range and a.range or be allowed 24 | to extend beyond. Defaults to FALSE (no clipping)} 25 | } 26 | \value{ 27 | A trans object. The transform method for the object takes an r 28 | (radius) and a (angle) argument and returns a data.frame with x and y columns 29 | with rows for each element in r/a. The inverse method takes an x and y 30 | argument and returns a data.frame with r and a columns and rows for each 31 | element in x/y. 32 | } 33 | \description{ 34 | This function creates a trans object that converts radial data to their 35 | corresponding coordinates in cartesian space. The trans object is created for 36 | a specific radius and angle range that will be mapped to the unit circle so 37 | data doesn't have to be normalized to 0-1 and 0-2*pi in advance. While there 38 | exists a clear mapping from radial to cartesian, the inverse is not true as 39 | radial representation is periodic. It is impossible to know how many 40 | revolutions around the unit circle a point has taken from reading its 41 | coordinates. The inverse function will always assume that coordinates are in 42 | their first revolution i.e. map them back within the range of a.range. 43 | } 44 | \note{ 45 | While trans objects are often used to modify scales in ggplot2, radial 46 | transformation is different as it is a coordinate transformation and takes 47 | two arguments. Consider it a trans version of coord_polar and use it to 48 | transform your data prior to plotting. 49 | } 50 | \examples{ 51 | # Some data in radial form 52 | rad <- data.frame(r = seq(1, 10, by = 0.1), a = seq(1, 10, by = 0.1)) 53 | 54 | # Create a transformation 55 | radial <- radial_trans(c(0, 1), c(0, 5)) 56 | 57 | # Get data in x, y 58 | cart <- radial$transform(rad$r, rad$a) 59 | 60 | # Have a look 61 | ggplot() + 62 | geom_path(aes(x = x, y = y), data = cart, color = 'forestgreen') + 63 | geom_path(aes(x = r, y = a), data = rad, color = 'firebrick') 64 | } 65 | -------------------------------------------------------------------------------- /man/scale_depth.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/scale-depth.R 3 | \name{scale_depth} 4 | \alias{scale_depth} 5 | \alias{scale_depth_continuous} 6 | \alias{scale_depth_discrete} 7 | \title{Scales for depth perception} 8 | \usage{ 9 | scale_depth(..., range = c(0, 0.3)) 10 | 11 | scale_depth_continuous(..., range = c(0, 0.3)) 12 | 13 | scale_depth_discrete(..., range = c(0, 0.3)) 14 | } 15 | \arguments{ 16 | \item{...}{arguments passed on to continuous_scale or discrete_scale} 17 | 18 | \item{range}{The relative range as related to the distance between the eyes 19 | and the paper plane.} 20 | } 21 | \description{ 22 | These scales serve to scale the depth aesthetic when creating stereographic 23 | plots. The range specifies the relative distance between the points and the 24 | paper plane in relation to the distance between the eyes and the paper plane 25 | i.e. a range of c(-0.5, 0.5) would put the highest values midways between 26 | the eyes and the image plane and the lowest values the same distance behind 27 | the image plane. To ensure a nice viewing experience these values should not 28 | exceed ~0.3 as it would get hard for the eyes to consolidate the two 29 | pictures. 30 | } 31 | \examples{ 32 | ggplot(mtcars) + 33 | geom_point(aes(mpg, disp, depth = cyl)) + 34 | scale_depth(range = c(-0.1, 0.25)) + 35 | facet_stereo() 36 | } 37 | -------------------------------------------------------------------------------- /man/scale_unit.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/scale-unit.R 3 | \name{scale_unit} 4 | \alias{scale_x_unit} 5 | \alias{scale_y_unit} 6 | \title{Position scales for units data} 7 | \usage{ 8 | scale_x_unit(...) 9 | 10 | scale_y_unit(...) 11 | } 12 | \arguments{ 13 | \item{...}{Passed on to \code{units::scale_x_units()} or \code{units::scale_y_units()}} 14 | } 15 | \description{ 16 | \ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} These are the default scales for the units 17 | class. These will usually be added automatically. To override manually, use 18 | \verb{scale_*_unit}. 19 | } 20 | \keyword{internal} 21 | -------------------------------------------------------------------------------- /man/shapeGrob.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/shape.R 3 | \name{shapeGrob} 4 | \alias{shapeGrob} 5 | \title{The grob powering geom_shape} 6 | \usage{ 7 | shapeGrob( 8 | x = c(0, 0.5, 1, 0.5), 9 | y = c(0.5, 1, 0.5, 0), 10 | id = NULL, 11 | id.lengths = NULL, 12 | expand = 0, 13 | radius = 0, 14 | default.units = "npc", 15 | name = NULL, 16 | gp = gpar(), 17 | vp = NULL 18 | ) 19 | } 20 | \arguments{ 21 | \item{x}{A numeric vector or unit object specifying x-locations.} 22 | 23 | \item{y}{A numeric vector or unit object specifying y-locations.} 24 | 25 | \item{id}{A numeric vector used to separate locations in \code{x} and 26 | \code{y} into multiple polygons. All locations with the same 27 | \code{id} belong to the same polygon.} 28 | 29 | \item{id.lengths}{A numeric vector used to separate locations in \code{x} and 30 | \code{y} into multiple polygons. Specifies consecutive blocks of 31 | locations which make up separate polygons.} 32 | 33 | \item{expand}{An expansion size to expand each shape with, given in units 34 | or a numeric refering to \code{default.units}} 35 | 36 | \item{radius}{The corner radius to apply to each shape, given in units 37 | or a numeric refering to \code{default.units}} 38 | 39 | \item{default.units}{A string indicating the default units to use 40 | if \code{x}, \code{y}, \code{width}, or \code{height} 41 | are only given as numeric vectors.} 42 | 43 | \item{name}{ A character identifier. } 44 | 45 | \item{gp}{An object of class \code{"gpar"}, typically the output 46 | from a call to the function \code{\link[grid]{gpar}}. This is basically 47 | a list of graphical parameter settings.} 48 | 49 | \item{vp}{A Grid viewport object (or NULL).} 50 | } 51 | \value{ 52 | A grob of class \code{shape} or, of \code{expand} and \code{radius} are \code{0} a 53 | regular polygon grob 54 | } 55 | \description{ 56 | This is the underlying grob constructor for \code{\link[=geom_shape]{geom_shape()}}. It is exported 57 | for others to use but with limited support 58 | } 59 | \keyword{internal} 60 | -------------------------------------------------------------------------------- /man/stat_err.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/errorbar.R 3 | \name{stat_err} 4 | \alias{stat_err} 5 | \title{Intervals in vertical and horizontal directions} 6 | \usage{ 7 | stat_err( 8 | mapping = NULL, 9 | data = NULL, 10 | geom = "segment", 11 | position = "identity", 12 | na.rm = FALSE, 13 | show.legend = NA, 14 | inherit.aes = TRUE, 15 | ... 16 | ) 17 | } 18 | \arguments{ 19 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and 20 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping 21 | at the top level of the plot. You must supply \code{mapping} if there is no plot 22 | mapping.} 23 | 24 | \item{data}{The data to be displayed in this layer. There are three 25 | options: 26 | 27 | If \code{NULL}, the default, the data is inherited from the plot 28 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 29 | 30 | A \code{data.frame}, or other object, will override the plot 31 | data. All objects will be fortified to produce a data frame. See 32 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 33 | 34 | A \code{function} will be called with a single argument, 35 | the plot data. The return value must be a \code{data.frame}, and 36 | will be used as the layer data. A \code{function} can be created 37 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 38 | 39 | \item{geom}{The geometric object to use to display the data, either as a 40 | \code{ggproto} \code{Geom} subclass or as a string naming the geom stripped of the 41 | \code{geom_} prefix (e.g. \code{"point"} rather than \code{"geom_point"})} 42 | 43 | \item{position}{Position adjustment, either as a string naming the adjustment 44 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 45 | position adjustment function. Use the latter if you need to change the 46 | settings of the adjustment.} 47 | 48 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with 49 | a warning. If \code{TRUE}, missing values are silently removed.} 50 | 51 | \item{show.legend}{logical. Should this layer be included in the legends? 52 | \code{NA}, the default, includes if any aesthetics are mapped. 53 | \code{FALSE} never includes, and \code{TRUE} always includes. 54 | It can also be a named logical vector to finely select the aesthetics to 55 | display.} 56 | 57 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics, 58 | rather than combining with them. This is most useful for helper functions 59 | that define both data and aesthetics and shouldn't inherit behaviour from 60 | the default plot specification, e.g. \code{\link[ggplot2:borders]{borders()}}.} 61 | 62 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 63 | often aesthetics, used to set an aesthetic to a fixed value, like 64 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 65 | to the paired geom/stat.} 66 | } 67 | \description{ 68 | \code{stat_err} draws intervals of points (\code{x}, \code{y}) in vertical (\code{ymin}, \code{ymax}) 69 | and horizontal (\code{xmin}, \code{xmax}) directions. 70 | } 71 | \section{Aesthetics}{ 72 | 73 | \code{stat_err()} understands the following aesthetics (required aesthetics are in 74 | bold): 75 | \itemize{ 76 | \item \strong{x} 77 | \item \strong{xmin} 78 | \item \strong{xmax} 79 | \item \strong{y} 80 | \item \strong{ymin} 81 | \item \strong{ymax} 82 | \item alpha 83 | \item color 84 | \item group 85 | \item linetype 86 | \item linewidth 87 | } 88 | } 89 | 90 | \examples{ 91 | library(ggplot2) 92 | 93 | x <- 1:3 94 | xmin <- x - 2.5 95 | xmax <- x + 2.5 96 | d <- data.frame( 97 | x = x, y = x, xmin = xmin, ymin = xmin, xmax = xmax, ymax = xmax, 98 | color = as.factor(x) 99 | ) 100 | ggplot( 101 | d, 102 | aes(x = x, y = y, xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, color = color) 103 | ) + 104 | stat_err(size = 2) 105 | 106 | } 107 | -------------------------------------------------------------------------------- /man/theme_no_axes.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/themes.R 3 | \name{theme_no_axes} 4 | \alias{theme_no_axes} 5 | \title{Theme without axes and gridlines} 6 | \usage{ 7 | theme_no_axes(base.theme = theme_bw()) 8 | } 9 | \arguments{ 10 | \item{base.theme}{The theme to use as a base for the new theme. Defaults to 11 | \code{\link[ggplot2:ggtheme]{ggplot2::theme_bw()}}.} 12 | } 13 | \value{ 14 | A modified version of base.theme 15 | } 16 | \description{ 17 | This theme is a simple wrapper around any complete theme that removes the 18 | axis text, title and ticks as well as the grid lines for plots where these 19 | have little meaning. 20 | } 21 | \examples{ 22 | p <- ggplot() + geom_point(aes(x = wt, y = qsec), data = mtcars) 23 | 24 | p + theme_no_axes() 25 | p + theme_no_axes(theme_grey()) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /man/trans_reverser.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trans.R 3 | \name{trans_reverser} 4 | \alias{trans_reverser} 5 | \title{Reverse a transformation} 6 | \usage{ 7 | trans_reverser(trans) 8 | } 9 | \arguments{ 10 | \item{trans}{A trans object or an object that can be converted to one using 11 | \code{\link[scales:new_transform]{scales::as.trans()}}} 12 | } 13 | \value{ 14 | A trans object 15 | } 16 | \description{ 17 | While the scales package export a reverse_trans object it does not allow for 18 | reversing of already transformed ranged - e.g. a reverse exp transformation 19 | is not possible. trans_reverser takes a trans object or something coercible 20 | to one and creates a reverse version of it. 21 | } 22 | \examples{ 23 | # Lets make a plot 24 | p <- ggplot() + 25 | geom_line(aes(x = 1:10, y = 1:10)) 26 | 27 | # scales already have a reverse trans 28 | p + scale_x_continuous(trans = 'reverse') 29 | 30 | # But what if you wanted to reverse an already log transformed scale? 31 | p + scale_x_continuous(trans = trans_reverser('log')) 32 | } 33 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggforce/4f73e82a24304035fe459d30d0dab2f8a7832cee/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Revdeps 2 | 3 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 82 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 0 new problems 6 | * We failed to check 0 packages 7 | 8 | -------------------------------------------------------------------------------- /revdep/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/bSpline.cpp: -------------------------------------------------------------------------------- 1 | #include "deBoor.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace cpp11::literals; 10 | 11 | #include 12 | 13 | cpp11::writable::doubles createKnots(int nControl, int degree) { 14 | int nKnots = nControl + degree + 1; 15 | 16 | cpp11::writable::doubles knots; 17 | knots.reserve(nKnots); 18 | for (int i = 0; i < nKnots; i++) { 19 | if (i < degree + 1) { 20 | knots.push_back(0); 21 | } else if (i < nKnots - degree) { 22 | knots.push_back(knots[i-1] + 1); 23 | } else { 24 | knots.push_back(knots[i-1]); 25 | } 26 | } 27 | return knots; 28 | } 29 | std::vector createOpenKnots(int nControl, int degree) { 30 | int nKnots = nControl + degree + 1; 31 | 32 | std::vector knots (nKnots, 0); 33 | for (int i = 0; i < nKnots; i++) { 34 | if (i < 1) knots[i] = 0; 35 | else knots[i] = knots[i-1] + 1; 36 | } 37 | return knots; 38 | } 39 | std::vector createControls(const cpp11::doubles& x, const cpp11::doubles& y) { 40 | int nControls = x.size(); 41 | std::vector controls(nControls, Point()); 42 | for (int i = 0; i < nControls; i++) { 43 | controls[i] = Point(x[i], y[i]); 44 | } 45 | return controls; 46 | } 47 | [[cpp11::register]] 48 | cpp11::writable::doubles_matrix<> splinePath(cpp11::doubles x, cpp11::doubles y, 49 | int degree, cpp11::doubles knots, 50 | int detail, cpp11::strings type) { 51 | std::vector controls = createControls(x, y); 52 | std::vector knots_vec(knots.begin(), knots.end()); 53 | if (type[0] == "closed") { 54 | controls.push_back(controls[0]); 55 | controls.push_back(controls[1]); 56 | controls.push_back(controls[2]); 57 | } 58 | cpp11::writable::doubles_matrix<> res(detail, 2); 59 | double zJump = (knots_vec[knots_vec.size()-1-degree] - knots_vec[degree]); 60 | if (type[0] == "clamped") { 61 | zJump /= double(detail-1); 62 | } else { 63 | zJump /= double(detail); 64 | } 65 | for (int i = 0; i < detail; i++) { 66 | Point point; 67 | if (i == detail-1 && type[0] == "clamped") { 68 | point = controls[controls.size()-1]; 69 | } else { 70 | double z = knots_vec[degree] + i * zJump; 71 | int zInt = whichInterval(z, knots_vec); 72 | point = deBoor(degree, degree, zInt, z, knots_vec, controls); 73 | } 74 | res(i, 0) = point.x; 75 | res(i, 1) = point.y; 76 | } 77 | return res; 78 | } 79 | [[cpp11::register]] 80 | cpp11::writable::list getSplines(cpp11::doubles x, cpp11::doubles y, 81 | cpp11::integers id, int detail, 82 | cpp11::strings type) { 83 | std::vector nControls; 84 | std::vector pathID; 85 | nControls.push_back(1); 86 | pathID.push_back(id[0]); 87 | for (int i = 1; i < id.size(); i++) { 88 | if (id[i] == pathID.back()) { 89 | nControls.back()++; 90 | } else { 91 | nControls.push_back(1); 92 | pathID.push_back(id[i]); 93 | } 94 | } 95 | int nPaths = nControls.size(); 96 | cpp11::writable::doubles_matrix<> paths(nPaths * detail, 2); 97 | cpp11::writable::integers pathsID(nPaths * detail); 98 | int controlsStart = 0; 99 | R_xlen_t pathStart = 0; 100 | for (int i = 0; i < nPaths; i++) { 101 | cpp11::writable::doubles knots; 102 | int degree = nControls[i] <= 3 ? nControls[i] - 1 : 3; 103 | if (type[0] == "clamped") { 104 | knots = createKnots(nControls[i], degree); 105 | } else if (type[0] == "open") { 106 | knots = createOpenKnots(nControls[i], degree); 107 | } else if (type[0] == "closed") { 108 | if (nControls[i] < 3) { 109 | cpp11::stop("At least 3 control points must be provided for closed b-splines"); 110 | } 111 | degree = 3; 112 | knots = createOpenKnots(nControls[i] + 3, degree); 113 | } else { 114 | cpp11::stop("type must be either \"open\", \"closed\", or \"clamped\""); 115 | } 116 | cpp11::writable::doubles x_tmp(x.begin() + controlsStart, x.begin() + controlsStart + nControls[i]); 117 | cpp11::writable::doubles y_tmp(y.begin() + controlsStart, y.begin() + controlsStart + nControls[i]); 118 | cpp11::doubles_matrix<> path = splinePath(x_tmp, y_tmp, degree, knots, detail, type); 119 | for (R_xlen_t j = 0; j < path.nrow(); ++j) { 120 | pathsID[pathStart + j] = pathID[i]; 121 | paths(pathStart + j, 0) = path(j, 0); 122 | paths(pathStart + j, 1) = path(j, 1); 123 | } 124 | controlsStart += nControls[i]; 125 | pathStart += path.nrow(); 126 | } 127 | return cpp11::writable::list({ 128 | "paths"_nm = paths, 129 | "pathID"_nm = pathsID 130 | }); 131 | } 132 | -------------------------------------------------------------------------------- /src/bezier.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cpp11::literals; 7 | 8 | #include 9 | 10 | double Bezier2(double t, const cpp11::doubles& w) { 11 | double t2 = t * t; 12 | double mt = 1-t; 13 | double mt2 = mt * mt; 14 | return w[0]*mt2 + w[1]*2*mt*t + w[2]*t2; 15 | } 16 | double Bezier3(double t, const cpp11::doubles& w) { 17 | double t2 = t * t; 18 | double t3 = t2 * t; 19 | double mt = 1-t; 20 | double mt2 = mt * mt; 21 | double mt3 = mt2 * mt; 22 | return w[0]*mt3 + 3*w[1]*mt2*t + 3*w[2]*mt*t2 + w[3]*t3; 23 | } 24 | [[cpp11::register]] 25 | cpp11::writable::doubles_matrix<> bezierPath(const cpp11::doubles& x, const cpp11::doubles& y, int detail) { 26 | cpp11::writable::doubles_matrix<> res(detail, 2); 27 | detail = detail - 1; 28 | double step = 1.0/detail; 29 | double t; 30 | if (x.size() == 3) { 31 | for (int i = 0; i < detail; i++) { 32 | t = i * step; 33 | res(i, 0) = Bezier2(t, x); 34 | res(i, 1) = Bezier2(t, y); 35 | } 36 | } else if (x.size() == 4) { 37 | for (int i = 0; i < detail; i++) { 38 | t = i * step; 39 | res(i, 0) = Bezier3(t, x); 40 | res(i, 1) = Bezier3(t, y); 41 | } 42 | } else { 43 | cpp11::stop("Only support for quadratic and cubic beziers"); 44 | } 45 | res(detail, 0) = x[x.size() - 1]; 46 | res(detail, 1) = y[y.size() - 1]; 47 | return res; 48 | } 49 | [[cpp11::register]] 50 | cpp11::writable::list getBeziers(const cpp11::doubles& x, const cpp11::doubles& y, 51 | const cpp11::integers& id, int detail) { 52 | std::vector nControls; 53 | std::vector pathID; 54 | nControls.push_back(1); 55 | pathID.push_back(id[0]); 56 | for (int i = 1; i < id.size(); i++) { 57 | if (id[i] == pathID.back()) { 58 | nControls.back()++; 59 | } else { 60 | nControls.push_back(1); 61 | pathID.push_back(id[i]); 62 | } 63 | } 64 | size_t nPaths = nControls.size(); 65 | cpp11::writable::doubles_matrix<> paths(nPaths * detail, 2); 66 | cpp11::writable::integers pathsID(nPaths * detail); 67 | int controlsStart = 0; 68 | R_xlen_t pathStart = 0; 69 | for (size_t i = 0; i < nPaths; i++) { 70 | cpp11::writable::doubles x_tmp(x.begin() + controlsStart, x.begin() + controlsStart + nControls[i]); 71 | cpp11::writable::doubles y_tmp(y.begin() + controlsStart, y.begin() + controlsStart + nControls[i]); 72 | cpp11::doubles_matrix<> path = bezierPath(x_tmp, y_tmp, detail); 73 | for (R_xlen_t j = 0; j < path.nrow(); ++j) { 74 | pathsID[pathStart + j] = pathID[i]; 75 | paths(pathStart + j, 0) = path(j, 0); 76 | paths(pathStart + j, 1) = path(j, 1); 77 | } 78 | controlsStart += nControls[i]; 79 | pathStart += path.nrow(); 80 | } 81 | return cpp11::writable::list({ 82 | "paths"_nm = paths, 83 | "pathID"_nm = pathsID 84 | }); 85 | } 86 | -------------------------------------------------------------------------------- /src/concaveman.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "concaveman.h" 6 | 7 | #include 8 | 9 | [[cpp11::register]] 10 | cpp11::writable::doubles_matrix<> concaveman_c(cpp11::doubles_matrix<> p, cpp11::integers h, 11 | double concavity, double threshold) { 12 | typedef std::array point_type; 13 | std::vector points(p.nrow()); 14 | for (auto i = 0; i < p.nrow(); ++i) { 15 | points[i] = {p(i, 0), p(i, 1)}; 16 | } 17 | std::vector hull(h.size()); 18 | for (auto i = 0; i < h.size(); ++i) { 19 | hull[i] = h[i]; 20 | } 21 | 22 | auto chull = concaveman(points, hull, concavity, threshold); 23 | 24 | cpp11::writable::doubles_matrix<> res(chull.size(), 2); 25 | 26 | for (size_t i = 0; i < chull.size(); ++i) { 27 | res(i, 0) = chull[i][0]; 28 | res(i, 1) = chull[i][1]; 29 | } 30 | 31 | return res; 32 | } 33 | -------------------------------------------------------------------------------- /src/cpp11.cpp: -------------------------------------------------------------------------------- 1 | // Generated by cpp11: do not edit by hand 2 | // clang-format off 3 | 4 | 5 | #include "cpp11/declarations.hpp" 6 | #include 7 | 8 | // bSpline.cpp 9 | cpp11::writable::doubles_matrix<> splinePath(cpp11::doubles x, cpp11::doubles y, int degree, cpp11::doubles knots, int detail, cpp11::strings type); 10 | extern "C" SEXP _ggforce_splinePath(SEXP x, SEXP y, SEXP degree, SEXP knots, SEXP detail, SEXP type) { 11 | BEGIN_CPP11 12 | return cpp11::as_sexp(splinePath(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(degree), cpp11::as_cpp>(knots), cpp11::as_cpp>(detail), cpp11::as_cpp>(type))); 13 | END_CPP11 14 | } 15 | // bSpline.cpp 16 | cpp11::writable::list getSplines(cpp11::doubles x, cpp11::doubles y, cpp11::integers id, int detail, cpp11::strings type); 17 | extern "C" SEXP _ggforce_getSplines(SEXP x, SEXP y, SEXP id, SEXP detail, SEXP type) { 18 | BEGIN_CPP11 19 | return cpp11::as_sexp(getSplines(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(id), cpp11::as_cpp>(detail), cpp11::as_cpp>(type))); 20 | END_CPP11 21 | } 22 | // bezier.cpp 23 | cpp11::writable::doubles_matrix<> bezierPath(const cpp11::doubles& x, const cpp11::doubles& y, int detail); 24 | extern "C" SEXP _ggforce_bezierPath(SEXP x, SEXP y, SEXP detail) { 25 | BEGIN_CPP11 26 | return cpp11::as_sexp(bezierPath(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(detail))); 27 | END_CPP11 28 | } 29 | // bezier.cpp 30 | cpp11::writable::list getBeziers(const cpp11::doubles& x, const cpp11::doubles& y, const cpp11::integers& id, int detail); 31 | extern "C" SEXP _ggforce_getBeziers(SEXP x, SEXP y, SEXP id, SEXP detail) { 32 | BEGIN_CPP11 33 | return cpp11::as_sexp(getBeziers(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(id), cpp11::as_cpp>(detail))); 34 | END_CPP11 35 | } 36 | // concaveman.cpp 37 | cpp11::writable::doubles_matrix<> concaveman_c(cpp11::doubles_matrix<> p, cpp11::integers h, double concavity, double threshold); 38 | extern "C" SEXP _ggforce_concaveman_c(SEXP p, SEXP h, SEXP concavity, SEXP threshold) { 39 | BEGIN_CPP11 40 | return cpp11::as_sexp(concaveman_c(cpp11::as_cpp>>(p), cpp11::as_cpp>(h), cpp11::as_cpp>(concavity), cpp11::as_cpp>(threshold))); 41 | END_CPP11 42 | } 43 | // ellipseEnclose.cpp 44 | cpp11::writable::data_frame enclose_ellip_points(cpp11::doubles x, cpp11::doubles y, cpp11::integers id, double tol); 45 | extern "C" SEXP _ggforce_enclose_ellip_points(SEXP x, SEXP y, SEXP id, SEXP tol) { 46 | BEGIN_CPP11 47 | return cpp11::as_sexp(enclose_ellip_points(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(id), cpp11::as_cpp>(tol))); 48 | END_CPP11 49 | } 50 | // enclose.cpp 51 | cpp11::writable::data_frame enclose_points(cpp11::doubles x, cpp11::doubles y, cpp11::integers id); 52 | extern "C" SEXP _ggforce_enclose_points(SEXP x, SEXP y, SEXP id) { 53 | BEGIN_CPP11 54 | return cpp11::as_sexp(enclose_points(cpp11::as_cpp>(x), cpp11::as_cpp>(y), cpp11::as_cpp>(id))); 55 | END_CPP11 56 | } 57 | // pointPath.cpp 58 | cpp11::writable::list points_to_path(cpp11::doubles_matrix<> pos, cpp11::list_of< cpp11::doubles_matrix<> > path, bool close); 59 | extern "C" SEXP _ggforce_points_to_path(SEXP pos, SEXP path, SEXP close) { 60 | BEGIN_CPP11 61 | return cpp11::as_sexp(points_to_path(cpp11::as_cpp>>(pos), cpp11::as_cpp >>>(path), cpp11::as_cpp>(close))); 62 | END_CPP11 63 | } 64 | 65 | extern "C" { 66 | static const R_CallMethodDef CallEntries[] = { 67 | {"_ggforce_bezierPath", (DL_FUNC) &_ggforce_bezierPath, 3}, 68 | {"_ggforce_concaveman_c", (DL_FUNC) &_ggforce_concaveman_c, 4}, 69 | {"_ggforce_enclose_ellip_points", (DL_FUNC) &_ggforce_enclose_ellip_points, 4}, 70 | {"_ggforce_enclose_points", (DL_FUNC) &_ggforce_enclose_points, 3}, 71 | {"_ggforce_getBeziers", (DL_FUNC) &_ggforce_getBeziers, 4}, 72 | {"_ggforce_getSplines", (DL_FUNC) &_ggforce_getSplines, 5}, 73 | {"_ggforce_points_to_path", (DL_FUNC) &_ggforce_points_to_path, 3}, 74 | {"_ggforce_splinePath", (DL_FUNC) &_ggforce_splinePath, 6}, 75 | {NULL, NULL, 0} 76 | }; 77 | } 78 | 79 | extern "C" attribute_visible void R_init_ggforce(DllInfo* dll){ 80 | R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); 81 | R_useDynamicSymbols(dll, FALSE); 82 | R_forceSymbols(dll, TRUE); 83 | } 84 | -------------------------------------------------------------------------------- /src/deBoor.cpp: -------------------------------------------------------------------------------- 1 | // Taken from https://chi3x10.wordpress.com/2009/10/18/de-boor-algorithm-in-c/ 2 | 3 | #include "deBoor.h" 4 | 5 | Point::Point() { 6 | x = 0.0; 7 | y = 0.0; 8 | } 9 | Point::Point(double xInit, double yInit) { 10 | x = xInit; 11 | y = yInit; 12 | } 13 | Point Point::operator=(const Point pt) { 14 | x = pt.x; 15 | y = pt.y; 16 | return *this; 17 | } 18 | Point Point::operator+(const Point pt) const { 19 | Point temp; 20 | temp.x = x + pt.x; 21 | temp.y = y + pt.y; 22 | return temp; 23 | } 24 | Point Point::operator*(double m) const { 25 | Point temp; 26 | temp.x = x*m; 27 | temp.y = y*m; 28 | return temp; 29 | } 30 | Point Point::operator/(double m) const { 31 | Point temp; 32 | temp.x = x/m; 33 | temp.y = y/m; 34 | return temp; 35 | } 36 | 37 | Point deBoor(int k, int degree, int i, double x, std::vector knots, 38 | std::vector ctrlPoints) { 39 | // Please see wikipedia page for detail 40 | // note that the algorithm here kind of traverses in reverse order 41 | // comapred to that in the wikipedia page 42 | if(k == 0) { 43 | return ctrlPoints[i]; 44 | } else { 45 | double alpha = (x - knots[i])/(knots[i+degree + 1 - k] - knots[i]); 46 | return (deBoor(k - 1, degree, i - 1, x, knots, ctrlPoints)*(1 - alpha) + 47 | deBoor(k - 1, degree, i, x, knots, ctrlPoints)*alpha); 48 | } 49 | } 50 | 51 | int whichInterval(double x, std::vector knots) { 52 | int ti = knots.size(); 53 | for(int i = 1; i < ti - 1; i++) { 54 | if(x < knots[i]) 55 | return(i - 1); 56 | else if(x == knots[ti - 1]) 57 | return(ti - 1); 58 | } 59 | return -1; 60 | } 61 | -------------------------------------------------------------------------------- /src/deBoor.h: -------------------------------------------------------------------------------- 1 | // Taken from https://chi3x10.wordpress.com/2009/10/18/de-boor-algorithm-in-c/ 2 | 3 | #include 4 | 5 | // Class for dealing with points/vectors in a 2-dimensional space 6 | class Point { 7 | public: 8 | double x; 9 | double y; 10 | 11 | Point(); 12 | Point(double xInit, double yInit); 13 | 14 | // copy assignment operator 15 | Point operator=(const Point pt); 16 | 17 | // Arithmatic operators 18 | Point operator+(const Point pt) const; 19 | Point operator*(double m) const; 20 | Point operator/(double m) const; 21 | }; 22 | 23 | // Find the interval in knots where x resides 24 | int whichInterval(double x, std::vector knots); 25 | 26 | // Calculate the position along the B-spline given by x 27 | // The spline is defined by the degree, knots and ctrlPoints. When calling k 28 | // should equal degree but due to the recursive nature k will decrease to 29 | // zero during recursion. i gives the interval in knots that x resides in 30 | Point deBoor(int k, int degree, int i, double x, std::vector knots, 31 | std::vector ctrlPoints); 32 | -------------------------------------------------------------------------------- /src/pointPath.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace cpp11::literals; 7 | 8 | #include 9 | #include 10 | 11 | double distSquared(std::pair p, std::pair p1) { 12 | double x = p1.first - p.first; 13 | double y = p1.second - p.second; 14 | return x * x + y * y; 15 | } 16 | std::pair projection(std::pair a, std::pair b, std::pair p, bool clamp) { 17 | if (a.first == b.first && a.second == b.second) return a; 18 | double length2 = distSquared(a, b); 19 | std::pair norm(b.first - a.first, b.second - a.second); 20 | std::pair pa(p.first - a.first, p.second - a.second); 21 | double t = (norm.first * pa.first + norm.second * pa.second) / length2; 22 | if (clamp) { 23 | t = std::max(0.0, std::min(1.0, t)); 24 | } 25 | norm.first = t * norm.first + a.first; 26 | norm.second = t * norm.second + a.second; 27 | return norm; 28 | } 29 | void dist_to_path(double x, double y, const cpp11::list_of< cpp11::doubles_matrix<> >& path, std::vector &res, bool closed_poly) { 30 | double shortest_dist = -1; 31 | std::pair closest; 32 | std::pair point(x, y); 33 | for (R_xlen_t i = 0; i < path.size(); ++i) { 34 | for (R_xlen_t j = 0; j < path[i].nrow(); ++j) { 35 | if (j == path[i].nrow() && !closed_poly) break; 36 | std::pair a(path[i](j, 0), path[i](j, 1)); 37 | R_xlen_t k = j == path[i].nrow() - 1 ? 0 : j + 1; 38 | std::pair b(path[i](k, 0), path[i](k, 1)); 39 | std::pair close = projection(a, b, point, true); 40 | double dist = std::sqrt(distSquared(point, close)); 41 | if (shortest_dist < 0 || dist < shortest_dist) { 42 | shortest_dist = dist; 43 | closest = close; 44 | } 45 | } 46 | } 47 | res.clear(); 48 | res.push_back(closest.first); 49 | res.push_back(closest.second); 50 | res.push_back(shortest_dist); 51 | } 52 | 53 | [[cpp11::register]] 54 | cpp11::writable::list points_to_path(cpp11::doubles_matrix<> pos, cpp11::list_of< cpp11::doubles_matrix<> > path, bool close) { 55 | std::vector res_container; 56 | cpp11::writable::doubles_matrix<> proj(pos.nrow(), 2); 57 | cpp11::writable::doubles dist(pos.nrow()); 58 | for (R_xlen_t i = 0; i < pos.nrow(); ++i) { 59 | dist_to_path(pos(i, 0), pos(i, 1), path, res_container, close); 60 | proj(i, 0) = res_container[0]; 61 | proj(i, 1) = res_container[1]; 62 | dist[i] = res_container[2]; 63 | } 64 | return cpp11::writable::list({ 65 | "projection"_nm = proj, 66 | "distance"_nm = dist 67 | }); 68 | } 69 | -------------------------------------------------------------------------------- /src/robust_predicate/basebase.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ------------------------------------------------------------ 4 | * basic types, macros, compiler-settings, etc... 5 | ------------------------------------------------------------ 6 | * 7 | * This program may be freely redistributed under the 8 | * condition that the copyright notices (including this 9 | * entire header) are not removed, and no compensation 10 | * is received through use of the software. Private, 11 | * research, and institutional use is free. You may 12 | * distribute modified versions of this code UNDER THE 13 | * CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE 14 | * TO IT IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE 15 | * ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE 16 | * MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR 17 | * NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution 18 | * of this code as part of a commercial system is 19 | * permissible ONLY BY DIRECT ARRANGEMENT WITH THE 20 | * AUTHOR. (If you are not directly supplying this 21 | * code to a customer, and you are instead telling them 22 | * how they can obtain it for free, then you are not 23 | * required to make any arrangement with me.) 24 | * 25 | * Disclaimer: Neither I nor: Columbia University, The 26 | * Massachusetts Institute of Technology, The 27 | * University of Sydney, nor The National Aeronautics 28 | * and Space Administration warrant this code in any 29 | * way whatsoever. This code is provided "as-is" to be 30 | * used at your own risk. 31 | * 32 | ------------------------------------------------------------ 33 | * 34 | * Last updated: 02 March, 2020 35 | * 36 | * Copyright 2013-2020 37 | * Darren Engwirda 38 | * de2363@columbia.edu 39 | * https://github.com/dengwirda/ 40 | * 41 | ------------------------------------------------------------ 42 | */ 43 | 44 | # pragma once 45 | 46 | # ifndef __BASEBASE__ 47 | # define __BASEBASE__ 48 | 49 | # include 50 | # include 51 | # include 52 | 53 | /* 54 | ------------------------------------------------------------ 55 | * push compiler settings 56 | ------------------------------------------------------------ 57 | */ 58 | 59 | # if defined(_MSC_VER) 60 | # pragma warning(disable:4127) // constant conditionals 61 | # pragma warning(disable:4503) // decorated name length 62 | 63 | # elif defined(__LLVM__) 64 | 65 | # elif defined(__GNUC__) 66 | 67 | # endif 68 | 69 | # define __assert assert 70 | 71 | /* 72 | ------------------------------------------------------------ 73 | * global data type alias 74 | ------------------------------------------------------------ 75 | */ 76 | 77 | typedef void void_type ; 78 | typedef bool bool_type ; 79 | typedef char char_type ; 80 | 81 | /* 82 | ------------------------------------------------------------ 83 | * function call decorator 84 | ------------------------------------------------------------ 85 | */ 86 | 87 | # define __inline_call inline 88 | # define __normal_call 89 | # define __static_call static 90 | # define __friend_call friend 91 | # define __nocast_call explicit 92 | 93 | /* 94 | ------------------------------------------------------------ 95 | * copy // move forwarding 96 | ------------------------------------------------------------ 97 | */ 98 | 99 | # define __copy(T, x) std::forward(x) 100 | # define __move(T, x) std::forward(x) 101 | 102 | /* 103 | ------------------------------------------------------------ 104 | * unused parameter macros 105 | ------------------------------------------------------------ 106 | */ 107 | 108 | # define __unreferenced(x) ((void) x) 109 | 110 | /* 111 | ------------------------------------------------------------ 112 | * no--alias pointer types 113 | ------------------------------------------------------------ 114 | */ 115 | 116 | # define __const_ptr(T) T const *__restrict 117 | # define __write_ptr(T) T *__restrict 118 | 119 | # define __const_ref(T) T const &__restrict 120 | # define __write_ref(T) T &__restrict 121 | 122 | /* 123 | ------------------------------------------------------------ 124 | * integer "flip" routines 125 | ------------------------------------------------------------ 126 | */ 127 | 128 | # define __isflip(__i) ( (__i) < 0) 129 | 130 | # define __doflip(__i) (-(__i) - 2) 131 | 132 | # define __unflip(__i) (((__i) < 0) \ 133 | ? __doflip(__i) : (__i) ) 134 | 135 | /* 136 | ------------------------------------------------------------ 137 | * integer "flip" routines 138 | ------------------------------------------------------------ 139 | */ 140 | 141 | # define __setbit(x,b) ((x)|= (1ULL<<(b))) 142 | 143 | # define __popbit(x,b) ((x)&= ~(1ULL<<(b))) 144 | 145 | # define __flpbit(x,b) ((x)^= (1ULL<<(b))) 146 | 147 | # define __chkbit(x,b) (!!((x)&(1ULL<<(b))) ) 148 | 149 | 150 | # endif//__BASEBASE__ 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/robust_predicate/geompred.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ------------------------------------------------------------ 4 | * robust geometric predicates, a'la shewchuk 5 | ------------------------------------------------------------ 6 | * 7 | * This program may be freely redistributed under the 8 | * condition that the copyright notices (including this 9 | * entire header) are not removed, and no compensation 10 | * is received through use of the software. Private, 11 | * research, and institutional use is free. You may 12 | * distribute modified versions of this code UNDER THE 13 | * CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE 14 | * TO IT IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE 15 | * ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE 16 | * MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR 17 | * NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution 18 | * of this code as part of a commercial system is 19 | * permissible ONLY BY DIRECT ARRANGEMENT WITH THE 20 | * AUTHOR. (If you are not directly supplying this 21 | * code to a customer, and you are instead telling them 22 | * how they can obtain it for free, then you are not 23 | * required to make any arrangement with me.) 24 | * 25 | * Disclaimer: Neither I nor: Columbia University, The 26 | * Massachusetts Institute of Technology, The 27 | * University of Sydney, nor The National Aeronautics 28 | * and Space Administration warrant this code in any 29 | * way whatsoever. This code is provided "as-is" to be 30 | * used at your own risk. 31 | * 32 | ------------------------------------------------------------ 33 | * 34 | * Last updated: 01 March, 2020 35 | * 36 | * Copyright 2020-- 37 | * Darren Engwirda 38 | * de2363@columbia.edu 39 | * https://github.com/dengwirda/ 40 | * 41 | ------------------------------------------------------------ 42 | */ 43 | 44 | # pragma once 45 | 46 | # ifndef __PREDICATES__ 47 | # define __PREDICATES__ 48 | 49 | # include "basebase.hpp" 50 | # include "mpfloats.hpp" 51 | 52 | # include 53 | 54 | # include "predicate/predicate_k.hpp" 55 | 56 | # endif//__PREDICATES__ 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /src/robust_predicate/mpfloats.hpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | ------------------------------------------------------------ 4 | * robust multi-precision floating-point expansions... 5 | ------------------------------------------------------------ 6 | * 7 | * This program may be freely redistributed under the 8 | * condition that the copyright notices (including this 9 | * entire header) are not removed, and no compensation 10 | * is received through use of the software. Private, 11 | * research, and institutional use is free. You may 12 | * distribute modified versions of this code UNDER THE 13 | * CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE 14 | * TO IT IN THE SAME FILE REMAIN UNDER COPYRIGHT OF THE 15 | * ORIGINAL AUTHOR, BOTH SOURCE AND OBJECT CODE ARE 16 | * MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR 17 | * NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution 18 | * of this code as part of a commercial system is 19 | * permissible ONLY BY DIRECT ARRANGEMENT WITH THE 20 | * AUTHOR. (If you are not directly supplying this 21 | * code to a customer, and you are instead telling them 22 | * how they can obtain it for free, then you are not 23 | * required to make any arrangement with me.) 24 | * 25 | * Disclaimer: Neither I nor: Columbia University, The 26 | * Massachusetts Institute of Technology, The 27 | * University of Sydney, nor The National Aeronautics 28 | * and Space Administration warrant this code in any 29 | * way whatsoever. This code is provided "as-is" to be 30 | * used at your own risk. 31 | * 32 | ------------------------------------------------------------ 33 | * 34 | * Last updated: 11 April, 2020 35 | * 36 | * Copyright 2020-- 37 | * Darren Engwirda 38 | * de2363@columbia.edu 39 | * https://github.com/dengwirda/ 40 | * 41 | ------------------------------------------------------------ 42 | */ 43 | 44 | # pragma once 45 | 46 | # ifndef __MP_FLOATS__ 47 | # define __MP_FLOATS__ 48 | 49 | # include "basebase.hpp" 50 | 51 | namespace mp_float 52 | { 53 | typedef double real_type; 54 | typedef int indx_type; 55 | } 56 | 57 | # include 58 | # include 59 | # include 60 | 61 | // pragma STDC FENV_ACCESS ON 62 | 63 | # include "expansion/dd_float.hpp" 64 | # include "expansion/ia_float.hpp" 65 | # include "expansion/mp_float.hpp" 66 | 67 | # include "expansion/mp_utils.hpp" 68 | 69 | # endif//__MP_FLOATS__ 70 | 71 | 72 | 73 | --------------------------------------------------------------------------------