├── .github ├── .gitignore ├── CODE_OF_CONDUCT.md └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ ├── rhub.yaml │ └── test-coverage.yaml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── LICENSE.note ├── NAMESPACE ├── NEWS.md ├── R ├── aaa.R ├── autograph.R ├── cappedPath.R ├── connections.R ├── cpp11.R ├── data_flare.R ├── data_highschool.R ├── data_whigs.R ├── edge_colourbar.R ├── edge_direction.R ├── edges.R ├── facet_edges.R ├── facet_graph.R ├── facet_nodes.R ├── geom_axis_hive.R ├── geom_conn_bundle.R ├── geom_edge.R ├── geom_edge_arc.R ├── geom_edge_bend.R ├── geom_edge_bundle_force.R ├── geom_edge_bundle_minimal.R ├── geom_edge_bundle_path.R ├── geom_edge_density.R ├── geom_edge_diagonal.R ├── geom_edge_elbow.R ├── geom_edge_fan.R ├── geom_edge_hive.R ├── geom_edge_link.R ├── geom_edge_loop.R ├── geom_edge_parallel.R ├── geom_edge_point.R ├── geom_edge_sf.R ├── geom_edge_span.R ├── geom_edge_tile.R ├── geom_node_arc_bar.R ├── geom_node_circle.R ├── geom_node_point.R ├── geom_node_range.R ├── geom_node_sf.R ├── geom_node_text.R ├── geom_node_tile.R ├── geom_node_voronoi.R ├── geometry.R ├── gganimate.R ├── ggproto-classes.R ├── ggraph-package.R ├── ggraph.R ├── layout.R ├── layout_auto.R ├── layout_backbone.R ├── layout_cactustree.R ├── layout_centrality.R ├── layout_circlepack.R ├── layout_dendrogram.R ├── layout_eigen.R ├── layout_fabric.R ├── layout_focus.R ├── layout_hive.R ├── layout_htree.R ├── layout_igraph.R ├── layout_linear.R ├── layout_manual.R ├── layout_matrix.R ├── layout_metro.R ├── layout_partition.R ├── layout_pmds.R ├── layout_sf.R ├── layout_stress.R ├── layout_treemap.R ├── layout_unrooted.R ├── nodes.R ├── pack.R ├── parallelPath.R ├── reshape_add_margins.R ├── scale_edge_alpha.R ├── scale_edge_colour.R ├── scale_edge_fill.R ├── scale_edge_linetype.R ├── scale_edge_shape.R ├── scale_edge_size.R ├── scale_edge_width.R ├── scale_label_size.R ├── tbl_graph.R ├── textAlong.R ├── theme_graph.R ├── utils.R └── zzz.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── data ├── flare.rda ├── highschool.rda └── whigs.rda ├── man ├── autograph.Rd ├── facet_edges.Rd ├── facet_graph.Rd ├── facet_nodes.Rd ├── figures │ ├── README-unnamed-chunk-2-1.png │ ├── lifecycle-archived.svg │ ├── lifecycle-defunct.svg │ ├── lifecycle-deprecated.svg │ ├── lifecycle-experimental.svg │ ├── lifecycle-maturing.svg │ ├── lifecycle-questioning.svg │ ├── lifecycle-soft-deprecated.svg │ ├── lifecycle-stable.svg │ ├── lifecycle-superseded.svg │ └── logo.png ├── flare.Rd ├── geom_axis_hive.Rd ├── geom_conn_bundle.Rd ├── geom_edge_arc.Rd ├── geom_edge_bend.Rd ├── geom_edge_bundle_force.Rd ├── geom_edge_bundle_minimal.Rd ├── geom_edge_bundle_path.Rd ├── geom_edge_density.Rd ├── geom_edge_diagonal.Rd ├── geom_edge_elbow.Rd ├── geom_edge_fan.Rd ├── geom_edge_hive.Rd ├── geom_edge_link.Rd ├── geom_edge_loop.Rd ├── geom_edge_parallel.Rd ├── geom_edge_point.Rd ├── geom_edge_sf.Rd ├── geom_edge_span.Rd ├── geom_edge_tile.Rd ├── geom_node_arc_bar.Rd ├── geom_node_circle.Rd ├── geom_node_point.Rd ├── geom_node_range.Rd ├── geom_node_sf.Rd ├── geom_node_text.Rd ├── geom_node_tile.Rd ├── geom_node_voronoi.Rd ├── geometry.Rd ├── get_con.Rd ├── get_edges.Rd ├── get_nodes.Rd ├── ggraph-extensions.Rd ├── ggraph-package.Rd ├── ggraph.Rd ├── guide_edge_colourbar.Rd ├── guide_edge_coloursteps.Rd ├── guide_edge_direction.Rd ├── highschool.Rd ├── internal_extractors.Rd ├── layout_tbl_graph_auto.Rd ├── layout_tbl_graph_backbone.Rd ├── layout_tbl_graph_cactustree.Rd ├── layout_tbl_graph_centrality.Rd ├── layout_tbl_graph_circlepack.Rd ├── layout_tbl_graph_dendrogram.Rd ├── layout_tbl_graph_eigen.Rd ├── layout_tbl_graph_fabric.Rd ├── layout_tbl_graph_focus.Rd ├── layout_tbl_graph_hive.Rd ├── layout_tbl_graph_htree.Rd ├── layout_tbl_graph_igraph.Rd ├── layout_tbl_graph_linear.Rd ├── layout_tbl_graph_manual.Rd ├── layout_tbl_graph_matrix.Rd ├── layout_tbl_graph_metro.Rd ├── layout_tbl_graph_partition.Rd ├── layout_tbl_graph_pmds.Rd ├── layout_tbl_graph_sf.Rd ├── layout_tbl_graph_stress.Rd ├── layout_tbl_graph_treemap.Rd ├── layout_tbl_graph_unrooted.Rd ├── layout_to_table.Rd ├── makeContent.cappedpathgrob.Rd ├── makeContent.textalong.Rd ├── node_angle.Rd ├── pack_circles.Rd ├── qgraph.Rd ├── reexports.Rd ├── scale_edge_alpha.Rd ├── scale_edge_colour.Rd ├── scale_edge_fill.Rd ├── scale_edge_linetype.Rd ├── scale_edge_shape.Rd ├── scale_edge_size.Rd ├── scale_edge_width.Rd ├── scale_label_size.Rd ├── scale_type.ggraph_geometry.Rd ├── theme_graph.Rd └── whigs.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.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 ├── cactusTree.cpp ├── circlePack.cpp ├── cpp11.cpp ├── dendrogram.cpp ├── forceBundle.cpp ├── hTree.cpp ├── iciclePlot.cpp ├── lineCutter.cpp ├── nodes.cpp ├── nodes.h ├── pathAttr.cpp ├── treemap.cpp └── unrooted.cpp └── vignettes ├── Edges.Rmd ├── Layouts.Rmd ├── Nodes.Rmd ├── edge_meme_wide.jpg └── tidygraph.Rmd /.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/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/rhub2/blob/v1/inst/workflow/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub2::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/rhub2/actions/rhub-setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/rhub2/actions/rhub-checkout@v1 55 | - uses: r-hub/rhub2/actions/rhub-platform-info@v1 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/rhub2/actions/rhub-setup-deps@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/rhub2/actions/rhub-run-check@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | steps: 79 | - uses: r-hub/rhub2/actions/rhub-checkout@v1 80 | - uses: r-hub/rhub2/actions/rhub-setup-r@v1 81 | with: 82 | job-config: ${{ matrix.config.job-config }} 83 | token: ${{ secrets.RHUB_TOKEN }} 84 | - uses: r-hub/rhub2/actions/rhub-platform-info@v1 85 | with: 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | job-config: ${{ matrix.config.job-config }} 88 | - uses: r-hub/rhub2/actions/rhub-setup-deps@v1 89 | with: 90 | job-config: ${{ matrix.config.job-config }} 91 | token: ${{ secrets.RHUB_TOKEN }} 92 | - uses: r-hub/rhub2/actions/rhub-run-check@v1 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | -------------------------------------------------------------------------------- /.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 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | src/*.o 5 | src/*.so 6 | src/*.dll 7 | *Rproj 8 | .Rbuildignore 9 | inst/doc 10 | docs/ 11 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: ggraph 2 | Type: Package 3 | Title: An Implementation of Grammar of Graphics for Graphs and Networks 4 | Version: 2.2.1.9000 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(given = "RStudio", 12 | role = "cph")) 13 | Maintainer: Thomas Lin Pedersen 14 | Description: The grammar of graphics as implemented in ggplot2 is a poor fit for 15 | graph and network visualizations due to its reliance on tabular data input. 16 | ggraph is an extension of the ggplot2 API tailored to graph visualizations 17 | and provides the same flexible approach to building up plots layer by layer. 18 | License: MIT + file LICENSE 19 | Encoding: UTF-8 20 | LazyData: TRUE 21 | Imports: 22 | dplyr, 23 | ggforce (>= 0.3.1), 24 | grid, 25 | igraph (>= 1.0.0), 26 | scales, 27 | MASS, 28 | ggrepel, 29 | utils, 30 | stats, 31 | viridis, 32 | rlang, 33 | tidygraph, 34 | graphlayouts (>= 1.1.0), 35 | withr, 36 | cli, 37 | vctrs, 38 | lifecycle, 39 | memoise 40 | Suggests: 41 | network, 42 | knitr, 43 | rmarkdown, 44 | purrr, 45 | tibble, 46 | seriation, 47 | deldir, 48 | gganimate, 49 | covr, 50 | sf, 51 | sfnetworks 52 | LinkingTo: 53 | cpp11 54 | RoxygenNote: 7.3.1 55 | Depends: 56 | R (>= 2.10), 57 | ggplot2 (>= 3.5.0) 58 | VignetteBuilder: knitr 59 | URL: https://ggraph.data-imaginist.com, https://github.com/thomasp85/ggraph 60 | BugReports: https://github.com/thomasp85/ggraph/issues 61 | Roxygen: list(markdown = TRUE) 62 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2017 2 | COPYRIGHT HOLDER: Thomas Lin Pedersen 3 | -------------------------------------------------------------------------------- /LICENSE.note: -------------------------------------------------------------------------------- 1 | The circle packing and minimal enclosing circle algorithms used in the functions 2 | layout_igraph_circlepack() and pack_circles() have been implemented with great 3 | help and inspiration from the source code of D3.js. The use of any of these 4 | function are therefore furthermore under the D3.js license copied below: 5 | 6 | D3.js license ------------------------------------------------------------------ 7 | 8 | Copyright 2010-2016 Mike Bostock 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without modification, 12 | are permitted provided that the following conditions are met: 13 | 14 | * Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | * Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | * Neither the name of the author nor the names of contributors may be used to 22 | endorse or promote products derived from this software without specific prior 23 | written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 26 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 27 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 29 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 32 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 33 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 34 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | -------------------------------------------------------------------------------- /R/aaa.R: -------------------------------------------------------------------------------- 1 | utils::globalVariables(c( 2 | 'angle', 3 | 'center_size', 4 | 'circular', 5 | 'con.id', 6 | 'direction', 7 | 'edge.id', 8 | 'edge_x', 9 | 'end', 10 | 'from', 11 | 'height', 12 | 'r', 13 | 'r0', 14 | 'section', 15 | 'start', 16 | 'to', 17 | 'width', 18 | 'x', 19 | 'xend', 20 | 'xmin', 21 | 'xmax', 22 | 'y', 23 | 'yend' 24 | )) 25 | 26 | #' @rdname ggraph-extensions 27 | #' @format NULL 28 | #' @usage NULL 29 | #' @export 30 | StatFilter <- ggproto('StatFilter', StatIdentity, 31 | setup_data = function(data, params) { 32 | if (any(names(data) == 'filter')) { 33 | if (!is.logical(data$filter)) { 34 | cli::cli_abort('{.field filter} must be logical') 35 | } 36 | data <- data[data$filter, names(data) != 'filter'] 37 | } 38 | data 39 | }, 40 | default_aes = aes(filter = TRUE) 41 | ) 42 | #' @rdname ggraph-extensions 43 | #' @format NULL 44 | #' @usage NULL 45 | #' @export 46 | StatReverse <- ggproto('StatReverse', StatFilter, 47 | setup_data = function(data, params) { 48 | data <- StatFilter$setup_data(data, params) 49 | data[rev(seq_len(nrow(data))), ] 50 | } 51 | ) 52 | 53 | #' @rdname ggraph-extensions 54 | #' @format NULL 55 | #' @usage NULL 56 | #' @export 57 | StatFilterSf <- ggproto('StatFilterSf', StatSf, 58 | setup_data = function(data, params) { 59 | if (any(names(data) == 'filter')) { 60 | if (!is.logical(data$filter)) { 61 | cli::cli_abort('{.field filter} must be logical') 62 | } 63 | data <- data[data$filter, names(data) != 'filter'] 64 | } 65 | data 66 | }, 67 | default_aes = aes(filter = TRUE) 68 | ) 69 | 70 | aes_intersect <- function(aes1, aes2) { 71 | aes <- c(as.list(aes1), aes2[!names(aes2) %in% names(aes1)]) 72 | class(aes) <- 'uneval' 73 | aes 74 | } 75 | 76 | data_type <- function(data) { 77 | type <- attr(data, 'type_ggraph') 78 | if (is.null(type)) { 79 | if (inherits(data, 'layout_ggraph')) { 80 | return('node_ggraph') 81 | } else { 82 | return('other') 83 | } 84 | } 85 | type 86 | } 87 | 88 | # non-orderaltering version of make.unique 89 | make_unique <- function(x, sep = '.') { 90 | if (!anyDuplicated(x)) return(x) 91 | groups <- match(x, unique0(x)) 92 | suffix <- unsplit(lapply(split(x, groups), seq_along), groups) 93 | max_chars <- nchar(max(suffix)) 94 | suffix_format <- paste0('%0', max_chars, 'd') 95 | paste0(x, sep, sprintf(suffix_format, suffix)) 96 | } 97 | 98 | warn_dropped_vars <- function(layout, data) { 99 | overlap <- intersect(names(layout), names(data)) 100 | if (length(overlap) > 0 && !identical(as.list(layout[overlap]), as.list(data[overlap]))) { 101 | cli::cli_warn('Existing variables {.var {overlap}} overwritten by layout variables') 102 | } 103 | } 104 | 105 | combine_layout_nodes <- function(layout, nodes) { 106 | warn_dropped_vars(layout, nodes) 107 | cbind(layout, nodes[, !names(nodes) %in% names(layout), drop = FALSE]) 108 | } 109 | 110 | empty_data <- function(x) { 111 | length(x) == 0 || nrow(x) == 0 112 | } 113 | 114 | combine_aes <- function(aes1, aes2) { 115 | aes_all <- c(aes1[setdiff(names(aes1), names(aes2))], aes2) 116 | class(aes_all) <- class(aes1) 117 | aes_all 118 | } 119 | -------------------------------------------------------------------------------- /R/cpp11.R: -------------------------------------------------------------------------------- 1 | # Generated by cpp11: do not edit by hand 2 | 3 | cactusTree <- function(parent, order, weight, scale, overlap, upright) { 4 | .Call(`_ggraph_cactusTree`, parent, order, weight, scale, overlap, upright) 5 | } 6 | 7 | pack <- function(areas) { 8 | .Call(`_ggraph_pack`, areas) 9 | } 10 | 11 | circlePackLayout <- function(parent, weight) { 12 | .Call(`_ggraph_circlePackLayout`, parent, weight) 13 | } 14 | 15 | dendrogram_spread <- function(graph, starts, y, leaf, repel, pad, ratio) { 16 | .Call(`_ggraph_dendrogram_spread`, graph, starts, y, leaf, repel, pad, ratio) 17 | } 18 | 19 | force_bundle_iter <- function(edges_xy, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps) { 20 | .Call(`_ggraph_force_bundle_iter`, edges_xy, K, C, P, P_rate, S, I, I_rate, compatibility_threshold, eps) 21 | } 22 | 23 | hTree <- function(parent, order) { 24 | .Call(`_ggraph_hTree`, parent, order) 25 | } 26 | 27 | partitionTree <- function(parent, order, weight, height) { 28 | .Call(`_ggraph_partitionTree`, parent, order, weight, height) 29 | } 30 | 31 | cut_lines <- function(x, y, id, start_width, start_height, end_width, end_height, start_type, end_type) { 32 | .Call(`_ggraph_cut_lines`, x, y, id, start_width, start_height, end_width, end_height, start_type, end_type) 33 | } 34 | 35 | pathAttr <- function(group, alpha, width, lty, colour, ngroups) { 36 | .Call(`_ggraph_pathAttr`, group, alpha, width, lty, colour, ngroups) 37 | } 38 | 39 | splitTreemap <- function(parent, order, weight, width, height) { 40 | .Call(`_ggraph_splitTreemap`, parent, order, weight, width, height) 41 | } 42 | 43 | unrooted <- function(parent, order, length, daylight, tol, rotation_mod, maxiter) { 44 | .Call(`_ggraph_unrooted`, parent, order, length, daylight, tol, rotation_mod, maxiter) 45 | } 46 | -------------------------------------------------------------------------------- /R/data_flare.R: -------------------------------------------------------------------------------- 1 | #' The class hierarchy of the flare visualization library 2 | #' 3 | #' This dataset contains the graph that describes the class hierarchy for the 4 | #' [Flare](https://blokt.com/tool/prefuse-flare) ActionScript visualization library. It 5 | #' contains both the class hierarchy as well as the import connections between 6 | #' classes. This dataset has been used extensively in the D3.js documentation 7 | #' and examples and are included here to make it easy to redo the examples in 8 | #' ggraph. 9 | #' 10 | #' @format A list of three data.frames describing the software structure of 11 | #' flare: 12 | #' \describe{ 13 | #' \item{edges}{This data.frame maps the hierarchical structure of the class 14 | #' hierarchy as an edgelist, with the class in `from` being the superclass 15 | #' of the class in `to`.} 16 | #' \item{vertices}{This data.frame gives additional information on the classes. 17 | #' It contains the full name, size and short name of each class.} 18 | #' \item{imports}{This data.frame contains the class imports for each class 19 | #' implementation. The `from` column gives the importing class and the 20 | #' `to` column gives the import.} 21 | #' } 22 | #' 23 | #' @source The data have been adapted from the JSON downloaded from 24 | #' 25 | #' courtesy of Mike Bostock. The Flare framework is the work of the 26 | #' [UC Berkeley Visualization Lab](http://vis.berkeley.edu/). 27 | #' 28 | 'flare' 29 | -------------------------------------------------------------------------------- /R/data_highschool.R: -------------------------------------------------------------------------------- 1 | #' Friendship among high school boys 2 | #' 3 | #' This dataset shows the friendship among high school boys as assessed by the 4 | #' question: "What fellows here in school do you go around with most often?". 5 | #' The question was posed twice, with one year in between (1957 and 1958) and 6 | #' shows the evolution in friendship between the two timepoints. 7 | #' 8 | #' @format 9 | #' The graph is stored as an unnamed edgelist with a year attribute. 10 | #' \describe{ 11 | #' \item{from}{The boy answering the question} 12 | #' \item{to}{The boy being the answer to the question} 13 | #' \item{year}{The year the friendship was reported} 14 | #' } 15 | #' 16 | #' @source 17 | #' Coleman, J. S. *Introduction to Mathematical Sociology*. New York: Free 18 | #' Press, pp.450-451. 19 | #' 20 | 'highschool' 21 | -------------------------------------------------------------------------------- /R/data_whigs.R: -------------------------------------------------------------------------------- 1 | #' Membership network of American Whigs 2 | #' 3 | #' This dataset shows the membership of 136 colonial Americans in 5 whig 4 | #' organization and is a bipartite graph. The data appeared in the appendix to 5 | #' David Hackett Fischer's *Paul Revere's Ride* (Oxford University Press, 6 | #' 1995) and compiled by Kieran Healy for the blog post 7 | #' [Using Metadata to Find Paul Revere](https://kieranhealy.org/blog/archives/2013/06/09/using-metadata-to-find-paul-revere/). 8 | #' 9 | #' @format 10 | #' The data is stored as an incidence matrix with persons as rows and 11 | #' organizations as columns. A 0 means no membership while a one means 12 | #' membership. 13 | #' 14 | #' @source 15 | #' adapted from: 16 | #' 17 | #' Fischer, David H. (1995) *Paul Revere's Ride*. Oxford University Press 18 | #' 19 | 'whigs' 20 | -------------------------------------------------------------------------------- /R/edge_colourbar.R: -------------------------------------------------------------------------------- 1 | #' Colourbar legend for edges 2 | #' 3 | #' This function is equivalent to [ggplot2::guide_colourbar()] but 4 | #' works for edge aesthetics. 5 | #' 6 | #' @inheritParams ggplot2::guide_colourbar 7 | #' @inheritDotParams ggplot2::guide_colourbar 8 | #' 9 | #' @return A guide object 10 | #' 11 | #' @export 12 | guide_edge_colourbar <- function(..., available_aes = c("edge_colour", "edge_fill")) { 13 | guide <- guide_colourbar(..., available_aes = available_aes) 14 | guide$params$name <- 'edge_colourbar' 15 | guide 16 | } 17 | #' @rdname guide_edge_colourbar 18 | #' @export 19 | guide_edge_colorbar <- guide_edge_colourbar 20 | 21 | #' Coloursteps legend for edges 22 | #' 23 | #' This function is equivalent to [ggplot2::guide_coloursteps()] but 24 | #' works for edge aesthetics. 25 | #' 26 | #' @inheritParams ggplot2::guide_coloursteps 27 | #' @inheritParams ggplot2::guide_colourbar 28 | #' @inheritDotParams ggplot2::guide_colourbar 29 | #' 30 | #' @return A guide object 31 | #' 32 | #' @export 33 | guide_edge_coloursteps <- function(even.steps = TRUE, show.limits = NULL, ..., 34 | available_aes = c("edge_colour", "edge_fill")) { 35 | guide <- guide_coloursteps(even.steps = even.steps, show.limits = show.limits, 36 | ..., available_aes = available_aes) 37 | guide$params$name <- 'edge_coloursteps' 38 | guide 39 | } 40 | #' @rdname guide_edge_coloursteps 41 | #' @export 42 | guide_edge_colorsteps <- guide_edge_coloursteps 43 | -------------------------------------------------------------------------------- /R/facet_edges.R: -------------------------------------------------------------------------------- 1 | #' Create small multiples based on edge attributes 2 | #' 3 | #' This function is equivalent to [ggplot2::facet_wrap()] but only 4 | #' facets edges. Nodes are repeated in every panel. 5 | #' 6 | #' @inheritParams ggplot2::facet_wrap 7 | #' 8 | #' @family ggraph-facets 9 | #' 10 | #' @examples 11 | #' gr <- tidygraph::as_tbl_graph(highschool) 12 | #' 13 | #' ggraph(gr) + 14 | #' geom_edge_link() + 15 | #' geom_node_point() + 16 | #' facet_edges(~year) 17 | #' @export 18 | #' 19 | facet_edges <- function(facets, nrow = NULL, ncol = NULL, scales = 'fixed', 20 | shrink = TRUE, labeller = 'label_value', as.table = TRUE, 21 | switch = deprecated(), drop = TRUE, dir = 'h', 22 | strip.position = 'top') { 23 | # Work around non-lifecycle deprecation 24 | if (!lifecycle::is_present(switch) && utils::packageVersion('ggplot2') <= '3.3.6') { 25 | switch <- NULL 26 | } 27 | facet <- facet_wrap( 28 | facets = facets, nrow = nrow, ncol = ncol, 29 | scales = scales, shrink = shrink, labeller = labeller, 30 | as.table = as.table, switch = switch, drop = drop, 31 | dir = dir, strip.position = strip.position 32 | ) 33 | seed <- sample(.Machine$integer.max, 1L) 34 | facet$params$facets[] <- lapply(seq_along(facet$params$facets), function(i) { 35 | rlang::quo(withr::with_seed(seed, !!facet$params$facets[[i]])) 36 | }) 37 | ggproto(NULL, FacetEdges, 38 | shrink = shrink, 39 | params = facet$params 40 | ) 41 | } 42 | 43 | #' @rdname ggraph-extensions 44 | #' @format NULL 45 | #' @usage NULL 46 | #' @export 47 | FacetEdges <- ggproto('FacetEdges', FacetWrap, 48 | compute_layout = function(data, params) { 49 | plot_data <- data[[1]] 50 | data <- split(data, vapply(data, data_type, character(1))) 51 | facet_data <- data$edge_ggraph 52 | 53 | panels <- FacetWrap$compute_layout(facet_data, params) 54 | node_placement <- rep(list(plot_data$.ggraph.index), nrow(panels)) 55 | names(node_placement) <- as.character(seq_along(node_placement)) 56 | attr(panels, 'node_placement') <- node_placement 57 | panels 58 | }, 59 | map_data = function(data, layout, params) { 60 | switch( 61 | data_type(data), 62 | node_ggraph = { 63 | node_map <- rep(list(data), length(attr(layout, 'node_placement'))) 64 | panel <- rep(seq_along(node_map), vapply(node_map, nrow, numeric(1))) 65 | node_map <- vec_rbind(!!!node_map) 66 | node_map$PANEL <- factor(panel, levels = levels(layout$PANEL)) 67 | node_map 68 | }, 69 | edge_ggraph = , { 70 | FacetWrap$map_data(data, layout, params) 71 | } 72 | ) 73 | } 74 | ) 75 | -------------------------------------------------------------------------------- /R/facet_nodes.R: -------------------------------------------------------------------------------- 1 | #' Create small multiples based on node attributes 2 | #' 3 | #' This function is equivalent to [ggplot2::facet_wrap()] but only 4 | #' facets nodes. Edges are drawn if their terminal nodes are both present in a 5 | #' panel. 6 | #' 7 | #' @inheritParams ggplot2::facet_wrap 8 | #' 9 | #' @family ggraph-facets 10 | #' 11 | #' @examples 12 | #' library(tidygraph) 13 | #' gr <- as_tbl_graph(highschool) %>% 14 | #' mutate(popularity = as.character(cut(centrality_degree(mode = 'in'), 15 | #' breaks = 3, 16 | #' labels = c('low', 'medium', 'high') 17 | #' ))) 18 | #' ggraph(gr) + 19 | #' geom_edge_link() + 20 | #' geom_node_point() + 21 | #' facet_nodes(~popularity) 22 | #' @export 23 | #' 24 | facet_nodes <- function(facets, nrow = NULL, ncol = NULL, scales = 'fixed', 25 | shrink = TRUE, labeller = 'label_value', as.table = TRUE, 26 | switch = deprecated(), drop = TRUE, dir = 'h', 27 | strip.position = 'top') { 28 | # Work around non-lifecycle deprecation 29 | if (!lifecycle::is_present(switch) && utils::packageVersion('ggplot2') <= '3.3.6') { 30 | switch <- NULL 31 | } 32 | facet <- facet_wrap( 33 | facets = facets, nrow = nrow, ncol = ncol, 34 | scales = scales, shrink = shrink, labeller = labeller, 35 | as.table = as.table, switch = switch, drop = drop, 36 | dir = dir, strip.position = strip.position 37 | ) 38 | seed <- sample(.Machine$integer.max, 1L) 39 | facet$params$facets[] <- lapply(seq_along(facet$params$facets), function(i) { 40 | rlang::quo(withr::with_seed(seed, !!facet$params$facets[[i]])) 41 | }) 42 | ggproto(NULL, FacetNodes, 43 | shrink = shrink, 44 | params = facet$params 45 | ) 46 | } 47 | 48 | #' @rdname ggraph-extensions 49 | #' @format NULL 50 | #' @usage NULL 51 | #' @export 52 | FacetNodes <- ggproto('FacetNodes', FacetWrap, 53 | compute_layout = function(data, params) { 54 | plot_data <- data[[1]] 55 | data <- split(data, vapply(data, data_type, character(1))) 56 | facet_data <- data$node_ggraph 57 | 58 | panels <- FacetWrap$compute_layout(facet_data, params) 59 | node_placement <- if (nrow(panels) == 1) { 60 | list(`1` = plot_data$ggraph_index) 61 | } else { 62 | node_map <- FacetWrap$map_data(plot_data, panels, params) 63 | node_map <- node_map[order(node_map$.ggraph.index), , drop = FALSE] 64 | split(node_map$.ggraph.index, node_map$PANEL) 65 | } 66 | attr(panels, 'node_placement') <- node_placement 67 | panels 68 | }, 69 | map_data = function(data, layout, params) { 70 | switch( 71 | data_type(data), 72 | edge_ggraph = { 73 | node_placement <- attr(layout, 'node_placement') 74 | edge_map <- Map(function(map, nodes) { 75 | map[map$from %in% nodes & map$to %in% nodes, , drop = FALSE] 76 | }, map = rep(list(data), length(node_placement)), nodes = node_placement) 77 | panel <- rep(seq_along(edge_map), vapply(edge_map, nrow, numeric(1))) 78 | edge_map <- vec_rbind(!!!edge_map) 79 | edge_map$PANEL <- factor(panel, levels = levels(layout$PANEL)) 80 | edge_map 81 | }, 82 | node_ggraph = , { 83 | FacetWrap$map_data(data, layout, params) 84 | } 85 | ) 86 | } 87 | ) 88 | -------------------------------------------------------------------------------- /R/geom_edge_point.R: -------------------------------------------------------------------------------- 1 | #' Draw edges as glyphs 2 | #' 3 | #' This geom draws edges as glyphs with their x-position defined by the 4 | #' x-position of the start node, and the y-position defined by the y-position of 5 | #' the end node. As such it will result in a matrix layout when used in 6 | #' conjunction with [layout_tbl_graph_matrix()] 7 | #' 8 | #' @inheritSection geom_edge_link Edge aesthetic name expansion 9 | #' 10 | #' @section Aesthetics: 11 | #' `geom_edge_point` understands the following 12 | #' aesthetics. Bold aesthetics are automatically set, but can be overwritten. 13 | #' 14 | #' - **x** 15 | #' - **y** 16 | #' - edge_shape 17 | #' - edge_colour 18 | #' - edge_size 19 | #' - edge_alpha 20 | #' - filter 21 | #' 22 | #' @inheritParams ggplot2::geom_point 23 | #' 24 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 25 | #' or [ggplot2::aes_()]. By default x, y, xend, yend, group and 26 | #' circular are mapped to x, y, xend, yend, edge.id and circular in the edge 27 | #' data. 28 | #' 29 | #' @param data The return of a call to `get_edges()` or a data.frame 30 | #' giving edges in correct format (see details for for guidance on the format). 31 | #' See [get_edges()] for more details on edge extraction. 32 | #' 33 | #' @param mirror Logical. Should edge points be duplicated on both sides of the 34 | #' diagonal. Intended for undirected graphs. Default to `FALSE` 35 | #' 36 | #' @author Thomas Lin Pedersen 37 | #' 38 | #' @family geom_edge_* 39 | #' 40 | #' @rdname geom_edge_point 41 | #' @name geom_edge_point 42 | #' 43 | #' @examples 44 | #' require(tidygraph) 45 | #' gr <- create_notable('zachary') %>% 46 | #' mutate(group = group_infomap()) %>% 47 | #' morph(to_split, group) %>% 48 | #' activate(edges) %>% 49 | #' mutate(edge_group = as.character(.N()$group[1])) %>% 50 | #' unmorph() 51 | #' 52 | #' ggraph(gr, 'matrix', sort.by = node_rank_hclust()) + 53 | #' geom_edge_point(aes(colour = edge_group), mirror = TRUE, edge_size = 3) + 54 | #' scale_y_reverse() + 55 | #' coord_fixed() + 56 | #' labs(edge_colour = 'Infomap Cluster') + 57 | #' ggtitle("Zachary' Karate Club") 58 | NULL 59 | 60 | #' @rdname geom_edge_point 61 | #' 62 | #' @export 63 | geom_edge_point <- function(mapping = NULL, data = get_edges(), 64 | position = 'identity', mirror = FALSE, 65 | show.legend = NA, ...) { 66 | mapping <- complete_edge_aes(mapping) 67 | mapping <- aes_intersect(mapping, aes(x = x, y = yend)) 68 | layer( 69 | data = data, mapping = mapping, stat = StatFilter, geom = GeomEdgePoint, 70 | position = position, show.legend = show.legend, inherit.aes = FALSE, 71 | params = list2(mirror = mirror, ...) 72 | ) 73 | } 74 | -------------------------------------------------------------------------------- /R/geom_edge_sf.R: -------------------------------------------------------------------------------- 1 | #' Draw edges as LINESTRINGs in geographical space 2 | #' 3 | #' This geom is equivalent in functionality to [ggplot2::geom_sf()] for `LINESTRING` 4 | #' geometries and allows for plotting of edges in their geographical space in 5 | #' different colours, linetypes and widths. 6 | #' 7 | #' @section Aesthetics: 8 | #' `geom_edge_sf` understand the following aesthetics. 9 | #' 10 | #' - alpha 11 | #' - colour 12 | #' - linetype 13 | #' - filter 14 | #' 15 | #' @inheritParams ggplot2::geom_sf 16 | #' 17 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 18 | #' or [ggplot2::aes_()]. By default geometry is mapped to the geometry in 19 | #' the edge data. 20 | #' 21 | #' @author Lorena Abad 22 | #' 23 | #' @family geom_edge_* 24 | #' 25 | #' @examples 26 | #' if (require("sfnetworks", quietly = TRUE)) { 27 | #' gr <- sfnetworks::as_sfnetwork(roxel) 28 | #' ggraph(gr, 'sf') + geom_edge_sf() 29 | #' } 30 | #' 31 | #' @export 32 | #' 33 | geom_edge_sf <- function(mapping = NULL, data = get_sf_edges(), 34 | position = 'identity', show.legend = NA, ...) { 35 | mapping <- complete_edge_aes(mapping) 36 | mapping <- aes_intersect(mapping, aes(geometry = geometry)) 37 | c( 38 | layer_sf( 39 | geom = GeomEdgeSf, data = data, mapping = mapping, stat = StatFilterSf, 40 | position = position, show.legend = show.legend, inherit.aes = FALSE, 41 | params = expand_edge_aes(list2(na.rm = FALSE, ...)) 42 | ), 43 | coord_sf(default = TRUE) 44 | ) 45 | } 46 | #' @rdname get_edges 47 | get_sf_edges <- function(){ 48 | function(layout) { 49 | edges <- sf::st_as_sf(attr(layout, "graph"), "edges") 50 | attr(edges, 'type_ggraph') <- 'edge_ggraph' 51 | edges 52 | } 53 | } 54 | 55 | #' @rdname ggraph-extensions 56 | #' @format NULL 57 | #' @usage NULL 58 | #' @export 59 | GeomEdgeSf = ggproto("GeomEdgeSf", GeomSf, 60 | draw_panel = function(data, panel_params, coords) { 61 | names(data) <- sub('edge_', '', names(data)) 62 | names(data)[names(data) == 'width'] <- 'linewidth' 63 | GeomSf$draw_panel(data, panel_params, coords) 64 | }, 65 | draw_key = GeomEdgePath$draw_key, 66 | default_aes = aes( 67 | edge_colour = 'black', edge_width = 0.5, edge_linetype = 1, 68 | edge_alpha = NA 69 | ), 70 | rename_size = FALSE 71 | ) 72 | -------------------------------------------------------------------------------- /R/geom_edge_tile.R: -------------------------------------------------------------------------------- 1 | #' Draw edges as glyphs 2 | #' 3 | #' This geom draws edges as tiles with their x-position defined by the 4 | #' x-position of the start node, and the y-position defined by the y-position of 5 | #' the end node. As such it will result in a matrix layout when used in 6 | #' conjunction with [layout_tbl_graph_matrix()] 7 | #' 8 | #' @inheritSection geom_edge_link Edge aesthetic name expansion 9 | #' 10 | #' @section Aesthetics: 11 | #' `geom_edge_tile` understands the following 12 | #' aesthetics. Bold aesthetics are automatically set, but can be overwritten. 13 | #' 14 | #' - **x** 15 | #' - **y** 16 | #' - edge_fill 17 | #' - edge_colour 18 | #' - edge_size 19 | #' - edge_alpha 20 | #' - filter 21 | #' 22 | #' @inheritParams ggplot2::geom_tile 23 | #' 24 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 25 | #' or [ggplot2::aes_()]. By default x, y, xend, yend, group and 26 | #' circular are mapped to x, y, xend, yend, edge.id and circular in the edge 27 | #' data. 28 | #' 29 | #' @param data The return of a call to `get_edges()` or a data.frame 30 | #' giving edges in correct format (see details for for guidance on the format). 31 | #' See [get_edges()] for more details on edge extraction. 32 | #' 33 | #' @param mirror Logical. Should edge points be duplicated on both sides of the 34 | #' diagonal. Intended for undirected graphs. Default to `FALSE` 35 | #' 36 | #' @author Thomas Lin Pedersen 37 | #' 38 | #' @family geom_edge_* 39 | #' 40 | #' @rdname geom_edge_tile 41 | #' @name geom_edge_tile 42 | #' 43 | #' @examples 44 | #' require(tidygraph) 45 | #' gr <- create_notable('zachary') %>% 46 | #' mutate(group = group_infomap()) %>% 47 | #' morph(to_split, group) %>% 48 | #' activate(edges) %>% 49 | #' mutate(edge_group = as.character(.N()$group[1])) %>% 50 | #' unmorph() 51 | #' 52 | #' ggraph(gr, 'matrix', sort.by = node_rank_hclust()) + 53 | #' geom_edge_tile(aes(fill = edge_group), mirror = TRUE) + 54 | #' scale_y_reverse() + 55 | #' coord_fixed() + 56 | #' labs(edge_colour = 'Infomap Cluster') + 57 | #' ggtitle("Zachary' Karate Club") 58 | NULL 59 | 60 | #' @rdname geom_edge_tile 61 | #' 62 | #' @export 63 | geom_edge_tile <- function(mapping = NULL, data = get_edges(), 64 | position = 'identity', mirror = FALSE, 65 | show.legend = NA, ...) { 66 | mapping <- complete_edge_aes(mapping) 67 | mapping <- aes_intersect(mapping, aes(x = x, y = yend)) 68 | layer( 69 | data = data, mapping = mapping, stat = StatFilter, geom = GeomEdgeTile, 70 | position = position, show.legend = show.legend, inherit.aes = FALSE, 71 | params = list2(mirror = mirror, ...) 72 | ) 73 | } 74 | -------------------------------------------------------------------------------- /R/geom_node_arc_bar.R: -------------------------------------------------------------------------------- 1 | #' Show nodes as thick arcs 2 | #' 3 | #' This geom is equivalent in functionality to [ggforce::geom_arc_bar()] 4 | #' and allows for plotting of nodes as arcs with an inner and outer radius 5 | #' scaled by the coordinate system. Its main use is currently in sunburst plots 6 | #' as created with circular partition layouts 7 | #' 8 | #' @section Aesthetics: 9 | #' `geom_node_point` understand the following aesthetics. Bold aesthetics are 10 | #' automatically set, but can be overwritten. 11 | #' 12 | #' - **x0** 13 | #' - **y0** 14 | #' - **r0** 15 | #' - **r** 16 | #' - **start** 17 | #' - **end** 18 | #' - alpha 19 | #' - colour 20 | #' - fill 21 | #' - shape 22 | #' - size 23 | #' - stroke 24 | #' - filter 25 | #' 26 | #' @inheritParams ggforce::geom_circle 27 | #' 28 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 29 | #' or [ggplot2::aes_()]. By default x and y are mapped to x0 and y0 in 30 | #' the node data. 31 | #' 32 | #' @author Thomas Lin Pedersen 33 | #' 34 | #' @family geom_node_* 35 | #' 36 | #' @examples 37 | #' require(tidygraph) 38 | #' gr <- tbl_graph(flare$vertices, flare$edges) 39 | #' ggraph(gr, 'partition', circular = TRUE, weight = size) + 40 | #' geom_node_arc_bar() 41 | #' @export 42 | #' @importFrom ggforce GeomArcBar 43 | #' 44 | geom_node_arc_bar <- function(mapping = NULL, data = NULL, position = 'identity', 45 | show.legend = NA, ...) { 46 | mapping <- aes_intersect(mapping, aes(x0 = 0, y0 = 0, r0 = r0, 47 | r = r, start = start, 48 | end = end)) 49 | layer( 50 | data = data, mapping = mapping, stat = StatNodeArcBar, geom = GeomArcBar, 51 | position = position, show.legend = show.legend, inherit.aes = FALSE, 52 | params = list2(...) 53 | ) 54 | } 55 | 56 | #' @rdname ggraph-extensions 57 | #' @format NULL 58 | #' @usage NULL 59 | #' @importFrom ggforce StatArcBar 60 | #' @export 61 | StatNodeArcBar <- ggproto('StatNodeArcBar', StatArcBar, 62 | setup_data = function(data, params) { 63 | StatFilter$setup_data(data, params) 64 | }, 65 | default_aes = aes(filter = TRUE) 66 | ) 67 | -------------------------------------------------------------------------------- /R/geom_node_circle.R: -------------------------------------------------------------------------------- 1 | #' Show nodes as circles 2 | #' 3 | #' This geom is equivalent in functionality to [ggforce::geom_circle()] 4 | #' and allows for plotting of nodes as circles with a radius scaled by the 5 | #' coordinate system. Because of the geoms reliance on the coordinate system 6 | #' it will only produce true circles when combined with 7 | #' [ggplot2::coord_fixed()] 8 | #' 9 | #' @section Aesthetics: 10 | #' `geom_node_circle` understand the following aesthetics. Bold aesthetics are 11 | #' automatically set, but can be overwritten. 12 | #' 13 | #' - **x0** 14 | #' - **y0** 15 | #' - **r** 16 | #' - alpha 17 | #' - colour 18 | #' - fill 19 | #' - shape 20 | #' - size 21 | #' - stroke 22 | #' - filter 23 | #' 24 | #' @inheritParams ggforce::geom_circle 25 | #' 26 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 27 | #' or [ggplot2::aes_()]. By default x and y are mapped to x0 and y0 in 28 | #' the node data. 29 | #' 30 | #' @author Thomas Lin Pedersen 31 | #' 32 | #' @family geom_node_* 33 | #' 34 | #' @examples 35 | #' require(tidygraph) 36 | #' gr <- tbl_graph(flare$vertices, flare$edges) 37 | #' ggraph(gr, 'circlepack', weight = size) + 38 | #' geom_node_circle() + 39 | #' coord_fixed() 40 | #' @export 41 | #' @importFrom ggforce GeomCircle 42 | #' 43 | geom_node_circle <- function(mapping = NULL, data = NULL, position = 'identity', 44 | show.legend = NA, ...) { 45 | mapping <- aes_intersect(mapping, aes(x0 = x, y0 = y, r = r)) 46 | layer( 47 | data = data, mapping = mapping, stat = StatNodeCircle, geom = GeomCircle, 48 | position = position, show.legend = show.legend, inherit.aes = FALSE, 49 | params = list2(...) 50 | ) 51 | } 52 | 53 | #' @rdname ggraph-extensions 54 | #' @format NULL 55 | #' @usage NULL 56 | #' @importFrom ggforce StatCircle 57 | #' @export 58 | StatNodeCircle <- ggproto('StatNodeCircle', StatCircle, 59 | setup_data = function(data, params) { 60 | StatFilter$setup_data(data, params) 61 | }, 62 | default_aes = aes(filter = TRUE) 63 | ) 64 | -------------------------------------------------------------------------------- /R/geom_node_point.R: -------------------------------------------------------------------------------- 1 | #' Show nodes as points 2 | #' 3 | #' This geom is equivalent in functionality to [ggplot2::geom_point()] 4 | #' and allows for simple plotting of nodes in different shapes, colours and sizes. 5 | #' 6 | #' @section Aesthetics: 7 | #' `geom_node_point` understand the following aesthetics. Bold aesthetics are 8 | #' automatically set, but can be overwritten. 9 | #' 10 | #' - **x** 11 | #' - **y** 12 | #' - alpha 13 | #' - colour 14 | #' - fill 15 | #' - shape 16 | #' - size 17 | #' - stroke 18 | #' - filter 19 | #' 20 | #' @inheritParams ggplot2::geom_point 21 | #' 22 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 23 | #' or [ggplot2::aes_()]. By default x and y are mapped to x and y in 24 | #' the node data. 25 | #' 26 | #' @author Thomas Lin Pedersen 27 | #' 28 | #' @family geom_node_* 29 | #' 30 | #' @examples 31 | #' require(tidygraph) 32 | #' gr <- create_notable('bull') %>% 33 | #' mutate(class = sample(letters[1:3], n(), replace = TRUE)) 34 | #' 35 | #' ggraph(gr, 'stress') + geom_node_point() 36 | #' @export 37 | #' 38 | geom_node_point <- function(mapping = NULL, data = NULL, position = 'identity', 39 | show.legend = NA, ...) { 40 | mapping <- aes_intersect(mapping, aes(x = x, y = y)) 41 | layer( 42 | data = data, mapping = mapping, stat = StatFilter, geom = GeomPoint, 43 | position = position, show.legend = show.legend, inherit.aes = FALSE, 44 | params = list2(...) 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /R/geom_node_range.R: -------------------------------------------------------------------------------- 1 | #' Show nodes as a line spanning a horizontal range 2 | #' 3 | #' This geom is most useful together with the [fabric][layout_tbl_graph_fabric] 4 | #' layout for showing the horizontal span of each node. 5 | #' 6 | #' @section Aesthetics: 7 | #' `geom_node_point` understand the following aesthetics. Bold aesthetics are 8 | #' automatically set, but can be overwritten. 9 | #' 10 | #' - **x** 11 | #' - **xend** 12 | #' - **y** 13 | #' - **yend** 14 | #' - alpha 15 | #' - colour 16 | #' - linetype 17 | #' - size 18 | #' - filter 19 | #' 20 | #' @inheritParams ggplot2::geom_linerange 21 | #' 22 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 23 | #' or [ggplot2::aes_()]. By default x is mapped to xmin, xend is mapped to xmax 24 | #' and y and yend are mapped to y in the node data. 25 | #' 26 | #' @author Thomas Lin Pedersen 27 | #' 28 | #' @family geom_node_* 29 | #' 30 | #' @examples 31 | #' require(tidygraph) 32 | #' gr <- as_tbl_graph(highschool) 33 | #' 34 | #' ggraph(gr, layout = 'fabric') + 35 | #' geom_node_range() 36 | #' @export 37 | #' 38 | geom_node_range <- function(mapping = NULL, data = NULL, position = 'identity', 39 | show.legend = NA, ...) { 40 | mapping <- aes_intersect(mapping, aes(x = xmin, xend = xmax, y = y, yend = y)) 41 | layer( 42 | data = data, mapping = mapping, stat = StatFilter, geom = GeomSegment, 43 | position = position, show.legend = show.legend, inherit.aes = FALSE, 44 | params = list2(...) 45 | ) 46 | } 47 | -------------------------------------------------------------------------------- /R/geom_node_sf.R: -------------------------------------------------------------------------------- 1 | #' Show nodes as POINTs in geographical space 2 | #' 3 | #' This geom is equivalent in functionality to [ggplot2::geom_sf()] for `POINT` 4 | #' geometries and allows for plotting of nodes in their geographical space in 5 | #' different shapes, colours and sizes. 6 | #' 7 | #' @section Aesthetics: 8 | #' `geom_node_sf` understand the following aesthetics. 9 | #' 10 | #' - alpha 11 | #' - colour 12 | #' - shape 13 | #' - size 14 | #' - filter 15 | #' 16 | #' @inheritParams ggplot2::geom_sf 17 | #' 18 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 19 | #' or [ggplot2::aes_()]. By default geometry is mapped to the geometry in 20 | #' the node data. 21 | #' 22 | #' @author Lorena Abad 23 | #' 24 | #' @family geom_node_* 25 | #' 26 | #' @examples 27 | #' library(tidygraph) 28 | #' 29 | #' if (require("sfnetworks", quietly = TRUE)) { 30 | #' gr <- sfnetworks::as_sfnetwork(roxel) 31 | #' ggraph(gr, 'sf') + 32 | #' geom_node_sf(aes(color = centrality_betweenness())) 33 | #' } 34 | #' 35 | #' @export 36 | #' 37 | geom_node_sf <- function(mapping = NULL, data = get_sf_nodes(), 38 | position = 'identity', show.legend = NA, ...) { 39 | mapping <- aes_intersect(mapping, aes(geometry = geometry)) 40 | c( 41 | layer_sf( 42 | geom = GeomSf, data = data, mapping = mapping, stat = StatFilterSf, 43 | position = position, show.legend = show.legend, inherit.aes = FALSE, 44 | params = list2(na.rm = FALSE, ...) 45 | ), 46 | coord_sf(default = TRUE) 47 | ) 48 | } 49 | 50 | #' @rdname get_nodes 51 | get_sf_nodes <- function(){ 52 | function(layout) { 53 | nodes <- sf::st_as_sf(layout) 54 | attr(nodes, 'type_ggraph') <- 'node_ggraph' 55 | nodes 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /R/geom_node_tile.R: -------------------------------------------------------------------------------- 1 | #' Draw the rectangles in a treemap 2 | #' 3 | #' A treemap is a space filling layout that recursively divides a rectangle to 4 | #' the children of the node. Often only the leaf nodes are drawn as nodes higher 5 | #' up in the hierarchy would obscure what is below. `geom_treemap` is a 6 | #' shorthand for `geom_node_treemap` as node is implicit in the case of 7 | #' treemap drawing 8 | #' 9 | #' @section Aesthetics: 10 | #' `geom_treemap` understand the following aesthetics. Bold aesthetics are 11 | #' automatically set, but can be overwritten. 12 | #' 13 | #' - **x** 14 | #' - **y** 15 | #' - **width** 16 | #' - **height** 17 | #' - alpha 18 | #' - colour 19 | #' - fill 20 | #' - size 21 | #' - stroke 22 | #' - filter 23 | #' 24 | #' @inheritParams ggplot2::geom_tile 25 | #' 26 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 27 | #' or [ggplot2::aes_()]. By default x, y, width and height are mapped to 28 | #' x, y, width and height in the node data. 29 | #' 30 | #' @author Thomas Lin Pedersen 31 | #' 32 | #' @family geom_node_* 33 | #' 34 | #' @examples 35 | #' # Create a graph of the flare class system 36 | #' library(tidygraph) 37 | #' flareGraph <- tbl_graph(flare$vertices, flare$edges) %>% 38 | #' mutate( 39 | #' class = map_bfs_chr(node_is_root(), .f = function(node, dist, path, ...) { 40 | #' if (dist <= 1) { 41 | #' return(shortName[node]) 42 | #' } 43 | #' path$result[[nrow(path)]] 44 | #' }) 45 | #' ) 46 | #' 47 | #' ggraph(flareGraph, 'treemap', weight = size) + 48 | #' geom_node_tile(aes(fill = class, filter = leaf, alpha = depth), colour = NA) + 49 | #' geom_node_tile(aes(linewidth = depth), colour = 'white') + 50 | #' scale_alpha(range = c(1, 0.5), guide = 'none') + 51 | #' scale_size(range = c(4, 0.2), guide = 'none') 52 | #' @export 53 | #' 54 | geom_node_tile <- function(mapping = NULL, data = NULL, position = 'identity', 55 | show.legend = NA, ...) { 56 | mapping <- aes_intersect(mapping, aes( 57 | x = x, y = y, width = width, height = height 58 | )) 59 | layer( 60 | data = data, mapping = mapping, stat = StatFilter, geom = GeomNodeTile, 61 | position = position, show.legend = show.legend, inherit.aes = FALSE, 62 | params = list2(...) 63 | ) 64 | } 65 | 66 | #' @rdname ggraph-extensions 67 | #' @format NULL 68 | #' @usage NULL 69 | #' @export 70 | #' 71 | GeomNodeTile <- ggproto('GeomNodeTile', GeomTile, 72 | default_aes = combine_aes(GeomTile$default_aes, aes(fill = NA, colour = 'black', width = 1, height = 1)), 73 | required_aes = c('x', 'y') 74 | ) 75 | -------------------------------------------------------------------------------- /R/geom_node_voronoi.R: -------------------------------------------------------------------------------- 1 | #' Show nodes as voronoi tiles 2 | #' 3 | #' This geom is equivalent in functionality to [ggforce::geom_voronoi_tile()] 4 | #' and allows for plotting of nodes as tiles from a voronoi tesselation. As with 5 | #' [ggforce::geom_voronoi_tile()] it is possible to restrict the size of the 6 | #' tile to a fixed radius, as well as round corners and expand/contract the 7 | #' tile. 8 | #' 9 | #' @section Aesthetics: 10 | #' `geom_node_voronoi` understand the following aesthetics. Bold aesthetics are 11 | #' automatically set, but can be overwritten. 12 | #' 13 | #' - **x** 14 | #' - **y** 15 | #' - alpha 16 | #' - colour 17 | #' - fill 18 | #' - shape 19 | #' - size 20 | #' - stroke 21 | #' - filter 22 | #' 23 | #' @inheritParams ggforce::geom_voronoi_tile 24 | #' 25 | #' @param mapping Set of aesthetic mappings created by [ggplot2::aes()] 26 | #' or [ggplot2::aes_()]. By default x and y are mapped to x and y in 27 | #' the node data and group set to `-1`. 28 | #' 29 | #' @author Thomas Lin Pedersen 30 | #' 31 | #' @family geom_node_* 32 | #' 33 | #' @examples 34 | #' require(tidygraph) 35 | #' gr <- create_notable('meredith') %>% 36 | #' mutate(group = sample(letters[1:4], n(), TRUE)) 37 | #' 38 | #' ggraph(gr) + 39 | #' geom_node_voronoi(aes(fill = group, colour = group), alpha = 0.3) + 40 | #' geom_edge_link(alpha = 0.3) + 41 | #' geom_node_point() 42 | #' 43 | #' # Use max.radius to make the tesselation more "node"-like 44 | #' ggraph(gr) + 45 | #' geom_node_voronoi(aes(fill = group, colour = group), alpha = 0.3, max.radius = 1) + 46 | #' geom_edge_link(alpha = 0.3) + 47 | #' geom_node_point() 48 | #' @export 49 | #' @importFrom ggforce GeomShape 50 | #' 51 | geom_node_voronoi <- function(mapping = NULL, data = NULL, position = 'identity', 52 | show.legend = NA, bound = NULL, eps = 1e-09, 53 | max.radius = NULL, normalize = FALSE, 54 | asp.ratio = 1, expand = 0, radius = 0, ...) { 55 | mapping <- aes_intersect(mapping, aes(x = x, y = y, group = -1)) 56 | layer( 57 | data = data, mapping = mapping, stat = StatNodeVoronoi, geom = GeomShape, 58 | position = position, show.legend = show.legend, inherit.aes = FALSE, 59 | params = list2(bound = bound, eps = eps, max.radius = max.radius, 60 | normalize = normalize, asp.ratio = asp.ratio, expand = expand, 61 | radius = radius, ...) 62 | ) 63 | } 64 | 65 | #' @rdname ggraph-extensions 66 | #' @format NULL 67 | #' @usage NULL 68 | #' @importFrom ggforce StatVoronoiTile 69 | #' @export 70 | StatNodeVoronoi <- ggproto('StatNodeVoronoi', StatVoronoiTile, 71 | finish_layer = function(data, params) { 72 | StatFilter$setup_data(data, params) 73 | }, 74 | default_aes = aes(filter = TRUE) 75 | ) 76 | -------------------------------------------------------------------------------- /R/gganimate.R: -------------------------------------------------------------------------------- 1 | # We need this so that edge geoms is consider 'points' by gganimate. This is 2 | # safe as all edges have the same number of points. We don't want to depend on 3 | # gganimate so we register it on load 4 | layer_type.GeomEdgePath <- function(x) 'point' 5 | -------------------------------------------------------------------------------- /R/ggproto-classes.R: -------------------------------------------------------------------------------- 1 | #' ggraph extensions to ggplot2 2 | #' 3 | #' This help page lists all exported ggproto classes defined by ggraph. In 4 | #' general these should be of no concern to the user as the main interface to 5 | #' the functionality is, as with ggplot2, the `geom_*` format. As opposed 6 | #' to ggplot2 there really aren't any use for separate `stat_*` functions 7 | #' as they are intimately linked to each geom and mixing and matching stats and 8 | #' geoms would only cause a lot of trouble. 9 | #' 10 | #' @details 11 | #' Many of the `geom_edge_*` geoms comes in different flavors dependent on 12 | #' the functionality required. There will always be a base geom and some will 13 | #' have a `geom_edge_*0` and `geom_edge_*2` version. The base geom 14 | #' will, in the case of multiple versions, draw the edge as a sequence of small 15 | #' segments. The different aesthetics will be repeated for each segment and a 16 | #' counter will be added the enumerates the progression of segments, so that a 17 | #' gradient of colour or size can be added along the edge by assigning the 18 | #' respective aesthetic to `after_stat(index)`. `geom_edge_*2` will also draw 19 | #' the edge as segments but will interpolate between the aesthetics at the end 20 | #' points. This makes it possible for an edge to interpolate node properties of 21 | #' its end nodes. `geom_edge_*2` is less performant than the base geom so 22 | #' use only when interpolation is needed. `geom_edge_*0` is a 23 | #' high-performance version that usually maps directly to a grid grob. It does 24 | #' not allow for drawing gradients or interpolations though, so use only for 25 | #' simple edge drawings. 26 | #' 27 | #' @name ggraph-extensions 28 | #' @rdname ggraph-extensions 29 | #' @keywords internal 30 | #' 31 | NULL 32 | -------------------------------------------------------------------------------- /R/ggraph-package.R: -------------------------------------------------------------------------------- 1 | #' @keywords internal 2 | '_PACKAGE' 3 | 4 | # The following block is used by usethis to automatically manage 5 | # roxygen namespace tags. Modify with care! 6 | ## usethis namespace: start 7 | #' @import ggplot2 tidygraph rlang vctrs 8 | #' @importFrom memoise memoise 9 | #' @importFrom lifecycle deprecated 10 | #' @useDynLib ggraph, .registration = TRUE 11 | ## usethis namespace: end 12 | NULL 13 | -------------------------------------------------------------------------------- /R/layout.R: -------------------------------------------------------------------------------- 1 | #' @rdname ggraph 2 | #' 3 | #' @aliases layout_ggraph 4 | #' 5 | #' @export 6 | create_layout <- function(graph, layout, circular, ...) { 7 | if (is_layout(layout)) { 8 | cli::cli_warn(c( 9 | 'Ignoring {.arg graph} as layout is already calculated', 10 | i = 'Pass the calculated layout to the {.arg graph} argument to silence this warning' 11 | )) 12 | return(layout) 13 | } 14 | UseMethod('create_layout', graph) 15 | } 16 | is_layout <- function(x) inherits(x, 'layout_ggraph') 17 | #' @rdname ggraph 18 | #' @export 19 | create_layout.default <- function(graph, layout, ...) { 20 | graph <- try_fetch(as_tbl_graph(graph), error = function(e) { 21 | cli::cli_abort('No layout function defined for objects of class {.cls {class(graph)[1]}}') 22 | }) 23 | create_layout(graph, layout, ...) 24 | } 25 | #' @rdname ggraph 26 | #' @export 27 | create_layout.layout_ggraph <- function(graph, ...) { 28 | graph 29 | } 30 | #' @export 31 | as.data.frame.layout_ggraph <- function(x, ...) { 32 | extra_attr <- names(attributes(x)) 33 | extra_attr <- extra_attr[!extra_attr %in% c('names', 'row.names')] 34 | attributes(x)[extra_attr] <- NULL 35 | class(x) <- 'data.frame' 36 | x 37 | } 38 | check_layout <- function(layout) { 39 | if (!is.data.frame(layout)) { 40 | cli::cli_abort('{.arg layout} must be a {.cls data.frame}') 41 | } 42 | if (!(is.numeric(layout$x) && is.numeric(layout$y))) { 43 | cli::cli_abort('{.arg layout} must contain numeric {.col x} and {.col y} columns') 44 | } 45 | graph <- attr(layout, 'graph') 46 | if (!is.tbl_graph(graph)) { 47 | cli::cli_abort('{.arg layout} must have a {.cls tbl_graph} as the {.arg graph} attribute') 48 | } 49 | if (nrow(layout) != gorder(graph)) { 50 | cli::cli_abort('{.arg layout} must contain the same number of rows as the number of nodes in the graph') 51 | } 52 | if (!'circular' %in% names(layout)) { 53 | layout$circular <- FALSE 54 | } 55 | if (!is.logical(layout$circular)) { 56 | cli::cli_abort('The {.col circular} column must be logical') 57 | } 58 | layout 59 | } 60 | -------------------------------------------------------------------------------- /R/layout_auto.R: -------------------------------------------------------------------------------- 1 | #' Automatically pick a layout based on graph type 2 | #' 3 | #' This function infers the layout from the graph structure and is the default 4 | #' when calling [ggraph()]. If an `x` and `y` argument is passed along, the 5 | #' manual layout is chosen. Otherwise if the graph is either a rooted tree or a 6 | #' rooted forest the layout will be `dendrogram` if the nodes contains a height 7 | #' variable or `tree` if not. If the tree is unrooted the `unrooted` layout will 8 | #' be used. If the tree is a DAG the `sygiyama` layout will be used. Otherwise 9 | #' the `stress` layout will be used (or `sparse_tree` if the graph contains more 10 | #' than 2000 nodes). 11 | #' 12 | #' @param graph A tbl_graph object 13 | #' 14 | #' @param circular Logical. Should the layout be transformed to a circular 15 | #' representation. Defaults to `FALSE`. Only applicable if the graph is a tree 16 | #' structure 17 | #' 18 | #' @param ... Arguments passed on to the chosen layout 19 | #' 20 | #' @return A data.frame with the columns `x`, `y`, `circular` as 21 | #' well as any information stored as node variables in the tbl_graph object. 22 | #' 23 | #' @family layout_tbl_graph_* 24 | #' 25 | #' @importFrom rlang .data quos 26 | #' 27 | layout_tbl_graph_auto <- function(graph, circular, ...) { 28 | if (all(c('x', 'y') %in% names(quos(...)))) { 29 | layout_tbl_graph_manual(graph, circular = circular, ...) 30 | } else if (with_graph(graph, graph_is_tree() || graph_is_forest())) { 31 | if (is.null(with_graph(graph, .N()[['height']]))) { 32 | cli::cli_inform('Using {.val tree} as default layout') 33 | layout_tbl_graph_igraph(graph, algorithm = 'tree', circular = circular, ...) 34 | } else { 35 | cli::cli_inform('Using {.val dendrogram} as default layout') 36 | layout_tbl_graph_dendrogram(graph, circular = circular, height = .data$height, ...) 37 | } 38 | } else if (with_graph(graph, graph_is_dag())) { 39 | cli::cli_inform('Using {.val sugiyama} as default layout') 40 | layout_tbl_graph_igraph(graph, algorithm = 'sugiyama', circular = circular, ...) 41 | } else if (with_graph(graph, graph_order()) < 2000) { 42 | cli::cli_inform('Using {.val stress} as default layout') 43 | layout_tbl_graph_stress(graph, circular = circular, ...) 44 | } else { 45 | cli::cli_inform('Using {.val sparse_stress} with 250 pivots as default layout') 46 | layout_tbl_graph_sparse_stress(graph, pivots = 250, circular = circular, ...) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /R/layout_backbone.R: -------------------------------------------------------------------------------- 1 | #' Place node to emphasize group structure 2 | #' 3 | #' This layout is optimised for drawing small-world types of graphs often found 4 | #' in social networks, where distinct groups are still highly connected to the 5 | #' remaining graph. Typical layouts struggle with this as they attempt to 6 | #' minimise the edge length of all edges equally. The backbone layout is based 7 | #' on weighing edges based on how well they hold together communities. The end 8 | #' result is that communities tend to stick together despite high 9 | #' interconnectivity. 10 | #' 11 | #' @param graph A tbl_graph object 12 | #' @param keep The fraction of edges to use for creating the backbone 13 | #' @param circular ignored 14 | #' 15 | #' @return A data.frame with the columns `x`, `y`, `circular` as 16 | #' well as any information stored as node variables in the tbl_graph object. 17 | #' Further an edge attribute called `backbone` is added giving whether the edge 18 | #' was selected as backbone. 19 | #' 20 | #' @references 21 | #' Nocaj, A., Ortmann, M., & Brandes, U. (2015). *Untangling the hairballs of 22 | #' multi-centered, small-world online social media networks.* Journal of Graph 23 | #' Algorithms and Applications: JGAA, 19(2), 595-618. 24 | #' 25 | #' @family layout_tbl_graph_* 26 | #' 27 | #' @author The underlying algorithm is implemented in the graphlayouts package 28 | #' by David Schoch 29 | #' 30 | #' @importFrom graphlayouts layout_as_backbone 31 | #' 32 | layout_tbl_graph_backbone <- function(graph, keep = 0.2, circular = FALSE) { 33 | layout <- layout_as_backbone(graph, keep = keep, backbone = TRUE) 34 | xy <- layout$xy 35 | nodes <- data_frame0(x = xy[,1], y = xy[,2], circular = FALSE) 36 | nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 37 | graph <- activate(graph, 'edges') 38 | graph <- mutate(graph, backbone = seq_len(graph_size()) %in% layout$backbone) 39 | attr(nodes, 'graph') <- activate(graph, 'nodes') 40 | nodes 41 | } 42 | -------------------------------------------------------------------------------- /R/layout_cactustree.R: -------------------------------------------------------------------------------- 1 | #' Calculate nodes as fractal circle buds 2 | #' 3 | #' The cactustree layout is a hierarchical layout optimised for use with 4 | #' hierarchical edge bundling ([geom_conn_bundle()]). It is a fractal layout 5 | #' that places node children as circles on the periphery of their parent circle, 6 | #' each circle scaled by the total weight of their children. 7 | #' 8 | #' @note 9 | #' cactustree is a layout intended for trees, that is, graphs where nodes 10 | #' only have one parent and zero or more children. If the provided graph does 11 | #' not fit this format an attempt to convert it to such a format will be made. 12 | #' 13 | #' @param graph An `tbl_graph` object 14 | #' 15 | #' @param direction The direction of the tree in the graph. `'out'` (default) 16 | #' means that parents point towards their children, while `'in'` means that 17 | #' children point towards their parent. 18 | #' 19 | #' @param weight An optional node variable to use as weight. If `NULL` all leaf 20 | #' nodes will be assigned a weight of `1`. 21 | #' 22 | #' @param scale_factor A scaling factor for the circles in the layout. The 23 | #' radius will be calculated as `total_weight ^ scale_factor` with `total_weight` 24 | #' being the weight of the node and all it's children. 25 | #' 26 | #' @param overlap How much is the center of child nodes offset from the 27 | #' periphery of their parent as a proportion of their own radius. 28 | #' 29 | #' @param upright Logical. Should the children of the root only be distributed 30 | #' around the top half of the root or all the way around. 31 | #' 32 | #' @param circular Logical. Should the layout be transformed to a circular 33 | #' representation. Ignored. 34 | #' 35 | #' @return A data.frame with the columns `x`, `y`, `r`, `leaf`, `depth`, 36 | #' `circular` as well as any information stored as node variables in the 37 | #' tbl_graph object. 38 | #' 39 | #' @references 40 | #' Dang, T., Forbes, A. (2017). *CactusTree: A Tree Drawing Approach 41 | #' for Hierarchical Edge Bundling*. 2017 IEEE Pacific Visualization Symposium, 42 | #' 210-214. https://doi.org/10.1109/PACIFICVIS.2017.8031596 43 | #' 44 | #' @family layout_tbl_graph_* 45 | #' 46 | layout_tbl_graph_cactustree <- function(graph, direction = "out", weight = NULL, scale_factor = 0.75, overlap = 0.5, upright = FALSE, circular = FALSE) { 47 | weight <- enquo(weight) 48 | weight <- eval_tidy(weight, .N()) 49 | if (is.null(weight)) { 50 | weight <- as.numeric(degree(graph, mode = direction) == 0) 51 | } 52 | hierarchy <- tree_to_hierarchy(graph, direction, NULL, weight, NULL) 53 | layout <- cactusTree( 54 | as.integer(hierarchy$parent), 55 | as.integer(hierarchy$order), 56 | as.numeric(hierarchy$weight), 57 | as.numeric(scale_factor), 58 | as.numeric(overlap), 59 | as.logical(upright) 60 | )[-1, ] 61 | nodes <- data_frame0( 62 | x = layout[, 1], 63 | y = layout[, 2], 64 | r = layout[, 3], 65 | circular = FALSE, 66 | leaf = degree(graph, mode = direction) == 0, 67 | depth = node_depth(graph, mode = direction) 68 | ) 69 | nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 70 | attr(nodes, 'graph') <- add_direction(graph, nodes) 71 | nodes 72 | } 73 | -------------------------------------------------------------------------------- /R/layout_centrality.R: -------------------------------------------------------------------------------- 1 | #' Place nodes in circles according to centrality measure 2 | #' 3 | #' This layout places nodes in circles with the radii relative to a given 4 | #' centrality measure. Under the hood it use stress majorisation to place nodes 5 | #' optimally given the radius constraint. 6 | #' 7 | #' @param graph A tbl_graph object 8 | #' @param centrality An expression evaluating to a centrality measure for the 9 | #' nodes. See the different `centrality_*()` algorithms in tidygraph for a 10 | #' selection. 11 | #' @param scale Should the centrality measure be scaled between 0 and 100 12 | #' @param tseq Transitioning steps 13 | #' @param group An expression evaluating to a grouping of the nodes. If given 14 | #' the layout will keep grouped nodes within an angle range of the origin 15 | #' @param shrink shrink the reserved angle range for a group to increase the 16 | #' gaps between groups 17 | #' @inheritParams layout_tbl_graph_stress 18 | #' 19 | #' @return A data.frame with the columns `x`, `y`, `circular`, `centrality` as 20 | #' well as any information stored as node variables in the tbl_graph object. 21 | #' 22 | #' @references 23 | #' Brandes, U., & Pich, C. (2011). *More flexible radial layout.* Journal of 24 | #' Graph Algorithms and Applications, 15(1), 157-173. 25 | #' 26 | #' @family layout_tbl_graph_* 27 | #' 28 | #' @author The underlying algorithm is implemented in the graphlayouts package 29 | #' by David Schoch 30 | #' 31 | #' @importFrom graphlayouts layout_with_centrality layout_with_centrality_group 32 | #' @importFrom rlang eval_tidy enquo 33 | layout_tbl_graph_centrality <- function(graph, centrality, scale = TRUE, 34 | niter = 500, tolerance = 1e-4, 35 | tseq = seq(0,1,0.2), group = NULL, 36 | shrink = 10, circular = FALSE) { 37 | centrality <- eval_tidy(enquo(centrality), .N()) 38 | group <- eval_tidy(enquo(group), .N()) 39 | if (is.null(group)) { 40 | xy <- layout_with_centrality(graph, cent = centrality, scale = scale, 41 | iter = niter, tol = tolerance, tseq = tseq) 42 | } else { 43 | xy <- layout_with_centrality_group(graph, cent = centrality, group = group, 44 | shrink = shrink, scale = scale, 45 | iter = niter, tol = tolerance, 46 | tseq = tseq) 47 | } 48 | 49 | nodes <- data_frame0(x = xy[,1],y = xy[,2], centrality = centrality, 50 | group = group, circular = FALSE) 51 | combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 52 | } 53 | -------------------------------------------------------------------------------- /R/layout_circlepack.R: -------------------------------------------------------------------------------- 1 | #' Calculate nodes as circles packed within their parent circle 2 | #' 3 | #' The circle packing algorithm is basically a treemap using circles instead of 4 | #' rectangles. Due to the nature of circles they cannot be packed as efficiently 5 | #' leading to increased amount of "empty space" as compared to a treemap. This 6 | #' can be beneficial though, as the added empty space can aid in visually 7 | #' showing the hierarchy. 8 | #' 9 | #' @details 10 | #' The circle packing is based on the algorithm developed by Weixin Wang and 11 | #' collaborators which tries to find the most dense packing of circles as they 12 | #' are added, one by one. This makes the algorithm very dependent on the order 13 | #' in which circles are added and it is possible that layouts could sometimes 14 | #' be optimized by choosing a different ordering. The algorithm for finding the 15 | #' enclosing circle is the randomized incremental algorithm proposed by Emo 16 | #' Welzl. Both of the above algorithms are the same as used in the D3.js 17 | #' implementation of circle packing and their C++ implementation in ggraph is 18 | #' inspired by Mike Bostocks JavaScript implementation. 19 | #' 20 | #' @note 21 | #' Circle packing is a layout intended for trees, that is, graphs where nodes 22 | #' only have one parent and zero or more children. If the provided graph does 23 | #' not fit this format an attempt to convert it to such a format will be made. 24 | #' 25 | #' @param graph An `tbl_graph` object 26 | #' 27 | #' @param weight An optional node variable to use as weight. Will only affect 28 | #' the weight of leaf nodes as the weight of non-leaf nodes are derived from 29 | #' their children. 30 | #' 31 | #' @param circular Logical. Should the layout be transformed to a circular 32 | #' representation. Ignored. 33 | #' 34 | #' @param sort.by The name of a node variable to sort the nodes by. 35 | #' 36 | #' @param direction The direction of the tree in the graph. `'out'` (default) 37 | #' means that parents point towards their children, while `'in'` means that 38 | #' children point towards their parent. 39 | #' 40 | #' @return A data.frame with the columns `x`, `y`, `r`, `leaf`, 41 | #' `depth`, `circular` as well as any information stored as node 42 | #' variables in the tbl_graph object. 43 | #' 44 | #' @references 45 | #' Wang, W., Wang, H. H., Dai, G., & Wang, H. (2006). *Visualization of 46 | #' large hierarchical data by circle packing*. Chi, 517-520. 47 | #' 48 | #' Welzl, E. (1991). *Smallest enclosing disks (balls and ellipsoids)*. New 49 | #' Results and New Trends in Computer Science, 359-370. 50 | #' 51 | #' @family layout_tbl_graph_* 52 | #' 53 | layout_tbl_graph_circlepack <- function(graph, weight = NULL, circular = FALSE, sort.by = NULL, direction = 'out') { 54 | weight <- enquo(weight) 55 | weight <- eval_tidy(weight, .N()) 56 | sort.by <- enquo(sort.by) 57 | sort.by <- eval_tidy(sort.by, .N()) 58 | hierarchy <- tree_to_hierarchy(graph, direction, sort.by, weight) 59 | nodes <- circlePackLayout( 60 | as.integer(hierarchy$parent), 61 | as.numeric(hierarchy$weight) 62 | )[-1, ] 63 | nodes <- data_frame0( 64 | x = nodes[, 1], 65 | y = nodes[, 2], 66 | r = nodes[, 3], 67 | circular = FALSE, 68 | leaf = degree(graph, mode = direction) == 0, 69 | depth = node_depth(graph, mode = direction) 70 | ) 71 | combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 72 | } 73 | -------------------------------------------------------------------------------- /R/layout_eigen.R: -------------------------------------------------------------------------------- 1 | #' Place nodes according to their eigenvalues 2 | #' 3 | #' This layout is based on the idea of spectral layouts where node coordinates 4 | #' are calculated directly by decomposing a matrix representation of the graph 5 | #' and extracting the eigenvectors. 6 | #' 7 | #' @param graph A tbl_graph object 8 | #' @param type The type of matrix to extract the eigenvectors from. Either 9 | #' `'laplacian'` or `'adjacency'` 10 | #' @param eigenvector The eigenvector to use for coordinates. Either `'smallest'` 11 | #' or `'largest'` 12 | #' @param circular ignored 13 | #' 14 | #' @return A data.frame with the columns `x`, `y`, `circular` as 15 | #' well as any information stored as node variables in the tbl_graph object. 16 | #' 17 | #' @family layout_tbl_graph_* 18 | #' 19 | #' @author The underlying algorithm is implemented in the graphlayouts package 20 | #' by David Schoch 21 | #' 22 | #' @importFrom graphlayouts layout_with_eigen 23 | layout_tbl_graph_eigen <- function(graph, type = 'laplacian', eigenvector = 'smallest', circular = FALSE) { 24 | type <- match.arg(type, c('laplacian', 'adjacency')) 25 | eigenvector <- match.arg(eigenvector, c('smallest', 'largest')) 26 | xy <- layout_with_eigen(graph, type = type, ev = eigenvector) 27 | nodes <- data_frame0(x = xy[,1],y = xy[,2], circular = FALSE) 28 | combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 29 | } 30 | -------------------------------------------------------------------------------- /R/layout_focus.R: -------------------------------------------------------------------------------- 1 | #' Place nodes in circles based on distance to a specific node 2 | #' 3 | #' This layout constrains node placement to a radius relative to its distance to 4 | #' a given node. It then uses stress majorisation to find an optimal node 5 | #' distribution according to this constraint. 6 | #' 7 | #' @param focus An expression evaluating to a selected node. Can either be a 8 | #' single integer or a logical vector with a single `TRUE` element. 9 | #' @inheritParams layout_tbl_graph_stress 10 | #' @inheritParams layout_tbl_graph_centrality 11 | #' 12 | #' @return A data.frame with the columns `x`, `y`, `circular`, `distance` as 13 | #' well as any information stored as node variables in the tbl_graph object. 14 | #' 15 | #' @references 16 | #' Brandes, U., & Pich, C. (2011). *More flexible radial layout.* Journal of 17 | #' Graph Algorithms and Applications, 15(1), 157-173. 18 | #' 19 | #' @family layout_tbl_graph_* 20 | #' 21 | #' @author The underlying algorithm is implemented in the graphlayouts package 22 | #' by David Schoch 23 | #' 24 | #' @importFrom graphlayouts layout_with_focus layout_with_focus_group 25 | #' @importFrom rlang eval_tidy enquo 26 | layout_tbl_graph_focus <- function(graph, focus, weights = NULL, niter = 500, tolerance = 1e-4, 27 | group = NULL, shrink = 10, circular = TRUE) { 28 | focus <- eval_tidy(enquo(focus), .N()) 29 | if (is.logical(focus)) focus <- which(focus)[1] 30 | 31 | weights <- eval_tidy(enquo(weights), .E()) 32 | if (is.null(weights)) { 33 | weights <- NA 34 | } 35 | 36 | group <- eval_tidy(enquo(group), .N()) 37 | 38 | if (is.null(group)) { 39 | layout <- layout_with_focus(graph, v = focus, weights = weights, iter = niter, 40 | tol = tolerance) 41 | } else { 42 | layout <- layout_with_focus_group(graph, v = focus, group = group, 43 | shrink = shrink, weights = weights, iter = niter, 44 | tol = tolerance) 45 | } 46 | 47 | xy <- layout$xy 48 | 49 | nodes <- data_frame0(x = xy[,1],y = xy[,2], distance = layout$distance, circular = FALSE) 50 | combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 51 | } 52 | -------------------------------------------------------------------------------- /R/layout_htree.R: -------------------------------------------------------------------------------- 1 | #' Layout binary trees in a fractal H formation 2 | #' 3 | #' This is a spac efficient layout only useful for binary trees. It is fractal 4 | #' and works by offsetting child nodes from their parent either horizontally or 5 | #' vertically depending on depth. The offset is decreased at each step by a 6 | #' factor of the square root of 2. 7 | #' 8 | #' @note 9 | #' H Tree is a layout intended for trees, that is, graphs where nodes 10 | #' only have one parent and zero or more children. If the provided graph does 11 | #' not fit this format an attempt to convert it to such a format will be made. 12 | #' 13 | #' @param graph An `tbl_graph` object 14 | #' 15 | #' @param sort.by The name of a node variable to sort the nodes by. 16 | #' 17 | #' @param direction The direction of the tree in the graph. `'out'` (default) 18 | #' means that parents point towards their children, while `'in'` means that 19 | #' children point towards their parent. 20 | #' 21 | #' @param circular Logical. Should the layout be transformed to a circular 22 | #' representation. Ignored 23 | #' 24 | #' @return A data.frame with the columns `x`, `y`, `leaf`, `depth`, `circular` 25 | #' as well as any information stored as node variables in the tbl_graph object. 26 | #' 27 | #' @family layout_tbl_graph_* 28 | #' 29 | #' @importFrom igraph degree count_components 30 | #' 31 | layout_tbl_graph_htree <- function(graph, sort.by = NULL, direction = 'out', circular = FALSE) { 32 | if (any(degree(graph, mode = direction) > 2)) { 33 | cli::cli_abort("H-Tree layouts can only be used with binary trees") 34 | } 35 | if (count_components(graph, "weak") != 1) { 36 | cli::cli_abort("H-Tree layouts can only be used with fully connected graphs") 37 | } 38 | sort.by <- enquo(sort.by) 39 | sort.by <- eval_tidy(sort.by, .N()) 40 | hierarchy <- tree_to_hierarchy(graph, direction, sort.by, NULL) 41 | layout <- hTree(as.integer(hierarchy$parent), as.integer(hierarchy$order))[-1, ] 42 | nodes <- data_frame0( 43 | x = layout[, 1], 44 | y = layout[, 2], 45 | circular = FALSE 46 | ) 47 | nodes$leaf <- degree(graph, mode = direction) == 0 48 | nodes$depth <- node_depth(graph, mode = direction) 49 | nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 50 | attr(nodes, 'graph') <- add_direction(graph, nodes) 51 | nodes 52 | } 53 | -------------------------------------------------------------------------------- /R/layout_linear.R: -------------------------------------------------------------------------------- 1 | #' Place nodes on a line or circle 2 | #' 3 | #' This layout puts all nodes on a line, possibly sorted by a node attribute. If 4 | #' `circular = TRUE` the nodes will be laid out on the unit circle instead. 5 | #' In the case where the `sort.by` attribute is numeric, the numeric values 6 | #' will be used as the x-position and it is thus possible to have uneven spacing 7 | #' between the nodes. 8 | #' 9 | #' @param graph An `tbl_graph` object 10 | #' 11 | #' @param circular Logical. Should the layout be transformed to a circular 12 | #' representation. Defaults to `FALSE`. 13 | #' 14 | #' @param sort.by The name of a node variable to sort the nodes by. 15 | #' 16 | #' @param use.numeric Logical. Should a numeric sort.by attribute be used as the 17 | #' actual x-coordinates in the layout. May lead to overlapping nodes. Defaults 18 | #' to FALSE 19 | #' 20 | #' @param offset If `circular = TRUE`, where should it begin. Defaults to 21 | #' `pi/2` which is equivalent to 12 o'clock. 22 | #' 23 | #' @param weight A weight for each node. Nodes will be spread out according to 24 | #' their weight so that nodes with heigher weight will have more space around 25 | #' them. Ignored if `use.numeric = TRUE` 26 | #' 27 | #' @return A data.frame with the columns `x`, `y`, `circular` as 28 | #' well as any information stored as node variables in the tbl_graph object. 29 | #' Further, if `circular = FALSE` a `width` column and if `circular = TRUE` a 30 | #' `start`, `end`, and `r0` column. 31 | #' 32 | #' @family layout_tbl_graph_* 33 | #' 34 | #' @importFrom igraph gorder 35 | #' 36 | layout_tbl_graph_linear <- function(graph, circular, sort.by = NULL, use.numeric = FALSE, offset = pi / 2, weight = NULL) { 37 | sort.by <- enquo(sort.by) 38 | sort.by <- eval_tidy(sort.by, .N()) 39 | weight <- enquo(weight) 40 | weight <- eval_tidy(weight, .N()) 41 | 42 | if (use.numeric && !is.null(weight)) { 43 | cli::cli_warn('Ignoring {.arg weight} when {.code use.numeric = TRUE}') 44 | } 45 | weight <- weight %||% rep(1, gorder(graph)) 46 | 47 | if (length(weight) != gorder(graph)) { 48 | cli::cli_abort('{.arg weight} must match the order of the graph') 49 | } 50 | if (any(weight < 0)) { 51 | cli::cli_abort("{.arg weight} must be positive") 52 | } 53 | 54 | if (!is.null(sort.by)) { 55 | if (length(sort.by) != gorder(graph)) { 56 | cli::cli_abort('{.arg sort.by} must match the order of the graph') 57 | } 58 | if (is.numeric(sort.by) && use.numeric) { 59 | x <- sort.by 60 | weight <- 0 61 | } else { 62 | x <- c(0, cumsum(weight[order(sort.by)])) 63 | x <- (x[-1] + x[-length(x)]) / 2 64 | x <- x[order(order(sort.by))] 65 | } 66 | } else { 67 | x <- c(0, cumsum(weight)) 68 | x <- (x[-1] + x[-length(x)]) / 2 69 | } 70 | nodes <- data_frame0(x = x, y = 0, width = weight) 71 | if (circular) { 72 | full_width <- sum(nodes$width) 73 | if (full_width > 0) { 74 | nodes$start <- 2 * pi * (nodes$x - nodes$width / 2) / full_width 75 | nodes$end <- 2 * pi * (nodes$x + nodes$width / 2) / full_width 76 | } else { 77 | full_width <- max(nodes$x) 78 | nodes$start <- 2 * pi * nodes$x / full_width 79 | nodes$end <- nodes$start 80 | } 81 | mid <- (nodes$start + nodes$end) / 2 82 | nodes$x <- sin(mid) 83 | nodes$y <- cos(mid) 84 | nodes$r0 <- 1 85 | } 86 | nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 87 | nodes$circular <- circular 88 | nodes 89 | } 90 | -------------------------------------------------------------------------------- /R/layout_manual.R: -------------------------------------------------------------------------------- 1 | #' Manually specify a layout for layout_tbl_graph 2 | #' 3 | #' This layout function lets you pass the node positions in manually. The 4 | #' supplied positions must match the order of the nodes in the tbl_graph 5 | #' 6 | #' @param graph An `tbl_graph` object 7 | #' 8 | #' @param x,y Expressions with the x and y positions of the nodes 9 | #' 10 | #' @param circular Ignored 11 | #' 12 | #' @return A data.frame with the columns `x`, `y`, `circular` as 13 | #' well as any information stored as node variables in the tbl_graph. 14 | #' 15 | #' @family layout_tbl_graph_* 16 | #' 17 | #' @importFrom rlang enquo eval_tidy quo_is_symbol 18 | #' 19 | layout_tbl_graph_manual <- function(graph, x, y, circular) { 20 | if (isTRUE(circular)) { 21 | cli::cli_warn('{.arg circular} argument ignored for manual layout') 22 | } 23 | x <- enquo(x) 24 | y <- enquo(y) 25 | nodes <- data_frame0( 26 | x = eval_tidy(x, .N()), 27 | y = eval_tidy(y, .N()), 28 | circular = FALSE 29 | ) 30 | nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 31 | nodes 32 | } 33 | -------------------------------------------------------------------------------- /R/layout_matrix.R: -------------------------------------------------------------------------------- 1 | #' Place nodes on a diagonal 2 | #' 3 | #' This layout puts all nodes on a diagonal, thus preparing the layout for use 4 | #' with [geom_edge_point()] resulting in a matrix layout. While matrix 5 | #' layouts excel in scalability, the interpretation of the visual is very 6 | #' dependent on the sorting of the nodes. Different sorting algorithms have been 7 | #' implemented in `tidygraph` and these can be used directly. Behrisch 8 | #' *et al.* (2016) have provided a nice overview of some of the different 9 | #' sorting algorithms and what insight they might bring, along with a rundown of 10 | #' different patterns to look out for. 11 | #' 12 | #' @param graph An `tbl_graph` object 13 | #' 14 | #' @param circular Ignored 15 | #' 16 | #' @param sort.by An expression providing the sorting of the nodes. If `NULL` 17 | #' the nodes will be ordered by their index in the graph. 18 | #' 19 | #' @return A data.frame with the columns `x`, `y`, `circular` as 20 | #' well as any information stored as node variables in the tbl_graph object. 21 | #' 22 | #' @family layout_tbl_graph_* 23 | #' 24 | #' @importFrom igraph gorder 25 | #' @importFrom rlang enquo eval_tidy 26 | #' 27 | #' @references 28 | #' Behrisch, M., Bach, B., Riche, N. H., Schreck, T., Fekete, J.-D. (2016). 29 | #' *Matrix Reordering Methods for Table and Network Visualization*. 30 | #' Computer Graphics Forum, 35: 693–716. \doi{10.1111/cgf.12935} 31 | #' 32 | layout_tbl_graph_matrix <- function(graph, circular = FALSE, sort.by = NULL) { 33 | sort.by <- enquo(sort.by) 34 | sort.by <- eval_tidy(sort.by, .N()) 35 | if (!is.null(sort.by)) { 36 | pos <- order(order(sort.by)) 37 | } else { 38 | pos <- seq_len(gorder(graph)) 39 | } 40 | nodes <- data_frame0(x = pos, y = pos, circular = FALSE) 41 | nodes <- combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 42 | nodes 43 | } 44 | -------------------------------------------------------------------------------- /R/layout_pmds.R: -------------------------------------------------------------------------------- 1 | #' Place nodes based on a multidimensional scaling of a set of pivot nodes 2 | #' 3 | #' This layout is similar to the 'mds' layout but uses only a subset of pivot 4 | #' nodes for the mds calculation, making it considerably faster and thus suited 5 | #' for large graphs 6 | #' 7 | #' @param graph A tbl_graph object 8 | #' @param pivots The number of pivot nodes 9 | #' @param weights An expression evaluated on the edge data to provide edge 10 | #' weights for the layout. Currently ignored for the sparse version 11 | #' @param circular ignored 12 | #' 13 | #' @return A data.frame with the columns `x`, `y`, `circular` as 14 | #' well as any information stored as node variables in the tbl_graph object. 15 | #' 16 | #' @references 17 | #' Brandes, U. and Pich, C. (2006). *Eigensolver Methods for Progressive 18 | #' Multidimensional Scaling of Large Data.* In International Symposium on Graph 19 | #' Drawing (pp. 42-53). Springer 20 | #' 21 | #' @family layout_tbl_graph_* 22 | #' 23 | #' @author The underlying algorithm is implemented in the graphlayouts package 24 | #' by David Schoch 25 | #' 26 | #' @importFrom graphlayouts layout_with_pmds 27 | layout_tbl_graph_pmds <- function(graph, pivots, weights = NULL, circular = FALSE) { 28 | weights <- eval_tidy(enquo(weights), .E()) 29 | if (is.null(weights)) weights <- NA 30 | xy <- layout_with_pmds(graph, pivots = pivots, weights = weights) 31 | nodes <- data_frame0(x = xy[,1], y = xy[,2], circular = FALSE) 32 | combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 33 | } 34 | -------------------------------------------------------------------------------- /R/layout_sf.R: -------------------------------------------------------------------------------- 1 | #' Place nodes on their geographical space 2 | #' 3 | #' This layout is built for objects of class `sfnetwork` and is meant to 4 | #' plot a graph on its geographical space, by extracting its X and Y coordinates 5 | #' 6 | #' @param graph An sfnetwork object 7 | #' @param circular ignored 8 | #' 9 | #' @importFrom tidygraph as_tbl_graph 10 | #' 11 | #' @return A data.frame with the columns `x`, `y`, `circular`. 12 | #' 13 | #' @family layout_tbl_graph_* 14 | layout_tbl_graph_sf <- function(graph, circular = FALSE) { 15 | # Check the presence of sf. 16 | check_installed("sf") 17 | # Check if network is an sfnetwork 18 | if (!inherits(graph, "sfnetwork")) { 19 | cli::cli_abort("The 'sf' layout needs an {.cls sfnetwork} graph.") 20 | } 21 | # Extract X and Y coordinates from the nodes 22 | graph <- activate(graph, "nodes") 23 | x <- sf::st_coordinates(graph)[,"X"] 24 | y <- sf::st_coordinates(graph)[,"Y"] 25 | # Create layout data frame 26 | nodes <- data_frame0(x = x, y = y, circular = FALSE) 27 | # Convert to tbl_graph to 'unstick' geometry column 28 | extra_data <- as_tibble(as_tbl_graph(graph), active = "nodes") 29 | nodes <- combine_layout_nodes(nodes, extra_data) 30 | attr(nodes, 'graph') <- graph 31 | nodes 32 | } 33 | -------------------------------------------------------------------------------- /R/layout_unrooted.R: -------------------------------------------------------------------------------- 1 | #' Create an unrooted layout using equal-angle or equal-daylight 2 | #' 3 | #' When drawing unrooted trees the standard dendrogram layout is a bad fit as it 4 | #' implicitly creates a visual root node. Instead it is possible to spread the 5 | #' leafs out on the plane without putting any special emphasis on a particular 6 | #' node using an unrooted layout. The standard algorithm is the equal angle 7 | #' algorithm, but it can struggle with optimising the leaf distribution for 8 | #' large trees with very uneven branch length. The equal daylight 9 | #' algorithm modifies the output of the equal angle algorithm to better disperse 10 | #' the leaves, at the cost of higher computational cost and the possibility of 11 | #' edge crossings for very large unbalanced trees. For standard sized trees the 12 | #' daylight algorithm is far superior and not too heavy so it is the default. 13 | #' 14 | #' @note 15 | #' Unrooted is a layout intended for undirected trees, that is, graphs with no 16 | #' cycles. If the provided graph does not fit this format an attempt to convert 17 | #' it to such a format will be made. 18 | #' 19 | #' @param graph A tbl_graph object 20 | #' @param daylight Should equal-daylight adjustments be made 21 | #' @param length An expression evaluating to the branch length of each edge 22 | #' @param tolerance The threshold for mean angular adjustment before terminating 23 | #' the daylight adjustment 24 | #' @param rotation_mod A modifier for the angular adjustment of each branch. Set 25 | #' it below 1 to let the daylight adjustment progress more slowly 26 | #' @param maxiter The maximum number of iterations in the the daylight 27 | #' adjustment 28 | #' @param circular ignored 29 | #' 30 | #' @return A data.frame with the columns `x`, `y`, `circular`, `leaf` as well as 31 | #' any information stored as node variables in the tbl_graph object. 32 | #' 33 | #' @references 34 | #' Felsenstein, J. (2004) *Drawing Trees*, in Inferring Phylogenies. Sinauer 35 | #' Assoc., pp 573-584 36 | #' 37 | #' @family layout_tbl_graph_* 38 | #' 39 | #' @importFrom igraph as.undirected gorder 40 | layout_tbl_graph_unrooted <- function(graph, daylight = TRUE, length = NULL, tolerance = 0.05, rotation_mod = 1, maxiter = 100, circular = FALSE) { 41 | extra_data <- as_tibble(graph, active = 'nodes') 42 | graph <- as_tbl_graph(as.undirected(graph)) 43 | length <- enquo(length) 44 | length <- eval_tidy(length, .E()) 45 | hierarchy <- tree_to_hierarchy(graph, 'out', seq_len(gorder(graph)), weight = NULL, length) 46 | layout <- unrooted( 47 | as.integer(hierarchy$parent), 48 | as.integer(hierarchy$order), 49 | as.numeric(hierarchy$height), 50 | as.logical(daylight), 51 | as.numeric(tolerance), 52 | as.numeric(rotation_mod), 53 | as.integer(maxiter) 54 | )[-1, ] 55 | nodes <- data_frame0( 56 | x = layout[, 1], 57 | y = layout[, 2], 58 | circular = FALSE, 59 | leaf = degree(graph) == 1 60 | ) 61 | combine_layout_nodes(nodes, as_tibble(graph, active = 'nodes')) 62 | } 63 | -------------------------------------------------------------------------------- /R/nodes.R: -------------------------------------------------------------------------------- 1 | #' Create a node extractor function 2 | #' 3 | #' This function returns another function that can extract nodes from a 4 | #' ggraph_layout object. As a ggraph_layout object is essentially a data.frame 5 | #' of nodes it might seem useless to provide this function, but since the node 6 | #' data is not necessarily available until after the `ggraph()` call it 7 | #' can be beneficial to be able to add information to the node data on a 8 | #' per-layer basis. Unlike [get_edges()] the use of `get_nodes` is not 9 | #' mandatory and is only required if additional data should be added to selected 10 | #' node layers. 11 | #' 12 | #' @param ... Additional data that should be cbind'ed together with the node 13 | #' data. Accepts expressions that will be evaluated on the node data in it's 14 | #' original order (irrespective of any reordering by the layout) 15 | #' 16 | #' @return A data.frame with the node data as well of any additional data 17 | #' supplied through `...` 18 | #' 19 | #' @family extractors 20 | #' 21 | #' @export 22 | #' 23 | get_nodes <- function(...) { 24 | dots <- enquos(...) 25 | function(layout) { 26 | layout_reorder <- layout[order(layout$.ggraph.orig_index), ] 27 | extra_data <- lapply(dots, function(x) { 28 | val <- eval_tidy(x, layout_reorder) 29 | rep(val, length.out = nrow(layout))[layout$.ggraph.orig_index] 30 | }) 31 | if (length(extra_data) > 0) { 32 | layout <- cbind( 33 | layout, 34 | data_frame0(!!!extra_data) 35 | ) 36 | } 37 | attr(layout, 'type_ggraph') <- 'node_ggraph' 38 | layout 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /R/pack.R: -------------------------------------------------------------------------------- 1 | #' Pack circles together 2 | #' 3 | #' This function is a direct interface to the circle packing algorithm used by 4 | #' \code{\link{layout_tbl_graph_circlepack}}. It takes a vector of sizes and 5 | #' returns the x and y position of each circle as a two-column matrix. 6 | #' 7 | #' @param areas A vector of circle areas 8 | #' 9 | #' @return A matrix with two columns and the same number of rows as the length 10 | #' of the "areas" vector. The matrix has the following attributes added: 11 | #' "enclosing_radius" giving the radius of the smallest enclosing circle, and 12 | #' "front_chain" giving the terminating members of the front chain (see 13 | #' Wang \emph{et al}. 2006). 14 | #' 15 | #' @references 16 | #' Wang, W., Wang, H. H., Dai, G., & Wang, H. (2006). \emph{Visualization of 17 | #' large hierarchical data by circle packing}. Chi, 517-520. 18 | #' 19 | #' @export 20 | #' 21 | #' @examples 22 | #' library(ggforce) 23 | #' sizes <- sample(10, 100, TRUE) 24 | #' 25 | #' position <- pack_circles(sizes) 26 | #' data <- data.frame(x = position[,1], y = position[,2], r = sqrt(sizes/pi)) 27 | #' 28 | #' ggplot() + 29 | #' geom_circle(aes(x0 = x, y0 = y, r = r), data = data, fill = 'steelblue') + 30 | #' geom_circle(aes(x0 = 0, y0 = 0, r = attr(position, 'enclosing_radius'))) + 31 | #' geom_polygon(aes(x = x, y = y), 32 | #' data = data[attr(position, 'front_chain'), ], 33 | #' fill = NA, 34 | #' colour = 'black') 35 | #' 36 | pack_circles <- function(areas) { 37 | pack(as.numeric(areas)) 38 | } 39 | -------------------------------------------------------------------------------- /R/parallelPath.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | #' @keywords internal 3 | makeContent.parallelPath <- function(x) { 4 | will_cap <- inherits(x, 'cappedpathgrob') 5 | if (!is.null(x$id)) { 6 | sep <- x$sep[!duplicated(x$id)] 7 | } 8 | x <- NextMethod() 9 | 10 | if (will_cap) { 11 | x$children[[1]]$sep <- sep[x$children[[1]]$id] 12 | if (inherits(x$children[[1]], 'segments')) { 13 | x$children[[1]] <- shift_segments(x$children[[1]]) 14 | } else { 15 | x$children[[1]] <- shift_paths(x$children[[1]]) 16 | } 17 | x 18 | } else if (inherits(x, 'segments')) { 19 | shift_segments(x) 20 | } else { 21 | shift_paths(x) 22 | } 23 | } 24 | 25 | shift_segments <- function(x) { 26 | x0_new <- convertX(x$x0, 'mm', TRUE) 27 | x1_new <- convertX(x$x1, 'mm', TRUE) 28 | y0_new <- convertY(x$y0, 'mm', TRUE) 29 | y1_new <- convertY(x$y1, 'mm', TRUE) 30 | 31 | sep <- convertWidth(x$sep, 'mm', TRUE) 32 | 33 | xdiff <- x1_new - x0_new 34 | ydiff <- y1_new - y0_new 35 | lengths <- sqrt(xdiff * xdiff + ydiff * ydiff) 36 | xshift <- -ydiff / lengths * sep 37 | yshift <- xdiff / lengths * sep 38 | 39 | x$x0 <- unit(x0_new + xshift, 'mm') 40 | x$x1 <- unit(x1_new + xshift, 'mm') 41 | x$y0 <- unit(y0_new + yshift, 'mm') 42 | x$y1 <- unit(y1_new + yshift, 'mm') 43 | 44 | x 45 | } 46 | 47 | shift_paths <- function(x) { 48 | first <- which(!duplicated(x$id)) 49 | last <- which(!duplicated(x$id, fromLast = TRUE)) 50 | 51 | sep <- convertWidth(x$sep[first], 'mm', TRUE) 52 | 53 | x_new <- convertX(x$x, 'mm', TRUE) 54 | y_new <- convertY(x$y, 'mm', TRUE) 55 | xdiff <- x_new[last] - x_new[first] 56 | ydiff <- y_new[last] - y_new[first] 57 | lengths <- sqrt(xdiff * xdiff + ydiff * ydiff) 58 | xshift <- -ydiff / lengths * sep 59 | yshift <- xdiff / lengths * sep 60 | 61 | x$x <- unit(x_new + xshift[x$id], 'mm') 62 | x$y <- unit(y_new + yshift[x$id], 'mm') 63 | 64 | x 65 | } 66 | -------------------------------------------------------------------------------- /R/reshape_add_margins.R: -------------------------------------------------------------------------------- 1 | # Inlined from reshape2 2 | reshape_add_margins <- function(df, vars, margins = TRUE) { 3 | margin_vars <- reshape_margins(vars, margins) 4 | 5 | # Return data frame if no margining necessary 6 | if (length(margin_vars) == 0) return(df) 7 | 8 | # Prepare data frame for addition of margins 9 | addAll <- function(x) { 10 | x <- addNA(x, TRUE) 11 | factor(x, levels = c(levels(x), "(all)"), exclude = NULL) 12 | } 13 | vars <- unique0(unlist(margin_vars)) 14 | df[vars] <- lapply(df[vars], addAll) 15 | 16 | rownames(df) <- NULL 17 | 18 | # Loop through all combinations of margin variables, setting 19 | # those variables to (all) 20 | margin_dfs <- lapply(margin_vars, function(vars) { 21 | df[vars] <- rep(list(factor("(all)")), length(vars)) 22 | df 23 | }) 24 | 25 | vec_rbind(!!!margin_dfs) 26 | } 27 | 28 | reshape_margins <- function(vars, margins = NULL) { 29 | if (is.null(margins) || identical(margins, FALSE)) return(NULL) 30 | 31 | all_vars <- unlist(vars) 32 | if (isTRUE(margins)) { 33 | margins <- all_vars 34 | } 35 | 36 | # Start by grouping margins by dimension 37 | dims <- lapply(vars, intersect, margins) 38 | 39 | # Next, ensure high-level margins include lower-levels 40 | dims <- mapply(function(vars, margin) { 41 | lapply(margin, downto, vars) 42 | }, vars, dims, SIMPLIFY = FALSE, USE.NAMES = FALSE) 43 | 44 | # Finally, find intersections across all dimensions 45 | seq_0 <- function(x) c(0, seq_along(x)) 46 | indices <- expand.grid(lapply(dims, seq_0), KEEP.OUT.ATTRS = FALSE) 47 | # indices <- indices[rowSums(indices) > 0, ] 48 | 49 | lapply(seq_len(nrow(indices)), function(i){ 50 | unlist(mapply("[", dims, indices[i, ], SIMPLIFY = FALSE)) 51 | }) 52 | } 53 | 54 | 55 | upto <- function(a, b) { 56 | b[seq_len(match(a, b, nomatch = 0))] 57 | } 58 | downto <- function(a, b) { 59 | rev(upto(a, rev(b))) 60 | } 61 | -------------------------------------------------------------------------------- /R/scale_edge_alpha.R: -------------------------------------------------------------------------------- 1 | #' Edge alpha scales 2 | #' 3 | #' This set of scales defines new alpha scales for edge geoms equivalent to the 4 | #' ones already defined by ggplot2. See [ggplot2::scale_alpha()] for 5 | #' more information. The different geoms will know whether to use edge scales or 6 | #' the standard scales so it is not necessary to write `edge_alpha` in 7 | #' the call to the geom - just use `alpha`. 8 | #' 9 | #' @return A ggproto object inheriting from `Scale` 10 | #' 11 | #' @family scale_edge_* 12 | #' 13 | #' @name scale_edge_alpha 14 | #' @rdname scale_edge_alpha 15 | #' 16 | NULL 17 | 18 | #' @rdname scale_edge_alpha 19 | #' 20 | #' @inheritParams ggplot2::scale_alpha 21 | #' 22 | #' @importFrom scales rescale_pal 23 | #' @export 24 | scale_edge_alpha <- function(..., range = c(0.1, 1)) { 25 | sc <- scale_alpha(..., range = range) 26 | sc$aesthetics <- 'edge_alpha' 27 | sc 28 | } 29 | 30 | #' @rdname scale_edge_alpha 31 | #' 32 | #' @export 33 | scale_edge_alpha_continuous <- scale_edge_alpha 34 | 35 | #' @rdname scale_edge_alpha 36 | #' 37 | #' 38 | #' @inheritParams ggplot2::scale_alpha_discrete 39 | #' 40 | #' @export 41 | scale_edge_alpha_discrete <- function(..., range = c(0.1, 1)) { 42 | sc <- scale_alpha_discrete(..., range = range) 43 | sc$aesthetics <- 'edge_alpha' 44 | sc 45 | } 46 | 47 | #' @rdname scale_edge_alpha 48 | #' 49 | #' 50 | #' @inheritParams ggplot2::scale_alpha_binned 51 | #' 52 | #' @export 53 | scale_edge_alpha_binned <- function(..., range = c(0.1, 1)) { 54 | sc <- scale_alpha_binned(..., range = range) 55 | sc$aesthetics <- 'edge_alpha' 56 | sc 57 | } 58 | 59 | #' @rdname scale_edge_alpha 60 | #' 61 | #' @inheritParams ggplot2::scale_alpha_manual 62 | #' 63 | #' @export 64 | scale_edge_alpha_manual <- function(..., values, breaks = waiver(), na.value = NA) { 65 | sc <- scale_alpha_manual(..., values = values, breaks = breaks, na.value = na.value) 66 | sc$aesthetics <- 'edge_alpha' 67 | sc 68 | } 69 | 70 | #' @rdname scale_edge_alpha 71 | #' 72 | #' @inheritParams ggplot2::scale_alpha_identity 73 | #' 74 | #' @importFrom scales identity_pal 75 | #' @export 76 | scale_edge_alpha_identity <- function(..., guide = 'none') { 77 | sc <- scale_alpha_identity(..., guide = guide) 78 | sc$aesthetics <- 'edge_alpha' 79 | sc 80 | } 81 | -------------------------------------------------------------------------------- /R/scale_edge_linetype.R: -------------------------------------------------------------------------------- 1 | #' Edge linetype scales 2 | #' 3 | #' This set of scales defines new linetype scales for edge geoms equivalent to 4 | #' the ones already defined by ggplot2. See 5 | #' [ggplot2::scale_linetype()] for more information. The different 6 | #' geoms will know whether to use edge scales or the standard scales so it is 7 | #' not necessary to write `edge_linetype` in the call to the geom - just 8 | #' use `linetype`. 9 | #' 10 | #' @return A ggproto object inheriting from `Scale` 11 | #' 12 | #' @family scale_edge_* 13 | #' 14 | #' @name scale_edge_linetype 15 | #' @rdname scale_edge_linetype 16 | #' 17 | NULL 18 | 19 | #' @rdname scale_edge_linetype 20 | #' 21 | #' @inheritParams ggplot2::scale_linetype 22 | #' @export 23 | scale_edge_linetype <- function(..., na.value = 'blank') { 24 | sc <- scale_linetype(..., na.value = na.value) 25 | sc$aesthetics <- 'edge_linetype' 26 | sc 27 | } 28 | #' @rdname scale_edge_linetype 29 | #' 30 | #' @export 31 | scale_edge_linetype_continuous <- function(...) { 32 | cli::cli_abort(c( 33 | "A continuous variable cannot be mapped to the {.field edge_linetype} aesthetic", 34 | "i" = "choose a different aesthetic or use {.fn scale_edge_linetype_binned}" 35 | )) 36 | } 37 | #' @rdname scale_edge_linetype 38 | #' 39 | #' @export 40 | scale_edge_linetype_discrete <- scale_edge_linetype 41 | #' @rdname scale_edge_linetype 42 | #' 43 | #' @export 44 | scale_edge_linetype_binned <- function(..., na.value = "blank") { 45 | sc <- scale_linetype_binned(..., na.value = na.value) 46 | sc$aesthetics <- 'edge_linetype' 47 | sc 48 | } 49 | #' @rdname scale_edge_linetype 50 | #' 51 | #' @inheritParams ggplot2::scale_linetype_manual 52 | #' 53 | #' @export 54 | scale_edge_linetype_manual <- function(..., values, breaks = waiver(), na.value = "blank") { 55 | sc <- scale_linetype_manual(..., values = values, breaks = breaks, na.value = na.value) 56 | sc$aesthetics <- 'edge_linetype' 57 | sc 58 | } 59 | #' @rdname scale_edge_linetype 60 | #' 61 | #' @inheritParams ggplot2::scale_linetype_identity 62 | #' @export 63 | scale_edge_linetype_identity <- function(..., guide = 'none') { 64 | sc <- scale_linetype_identity(..., guide = guide) 65 | sc$aesthetics <- 'edge_linetype' 66 | sc 67 | } 68 | -------------------------------------------------------------------------------- /R/scale_edge_shape.R: -------------------------------------------------------------------------------- 1 | #' Edge shape scales 2 | #' 3 | #' This set of scales defines new shape scales for edge geoms equivalent to the 4 | #' ones already defined by ggplot2. See [ggplot2::scale_shape()] for 5 | #' more information. The different geoms will know whether to use edge scales or 6 | #' the standard scales so it is not necessary to write `edge_shape` in 7 | #' the call to the geom - just use `shape`. 8 | #' 9 | #' @param guide Guide to use for this scale. 10 | #' 11 | #' @return A ggproto object inheriting from `Scale` 12 | #' 13 | #' @family scale_edge_* 14 | #' 15 | #' @name scale_edge_shape 16 | #' @rdname scale_edge_shape 17 | #' 18 | NULL 19 | 20 | #' @rdname scale_edge_shape 21 | #' 22 | #' @inheritParams ggplot2::scale_shape 23 | #' 24 | #' @export 25 | scale_edge_shape <- function(..., solid = TRUE) { 26 | sc <- scale_shape(..., solid = solid) 27 | sc$aesthetics <- 'edge_shape' 28 | sc 29 | } 30 | #' @rdname scale_edge_shape 31 | #' 32 | #' @export 33 | scale_edge_shape_discrete <- scale_edge_shape 34 | #' @rdname scale_edge_shape 35 | #' 36 | #' @export 37 | scale_edge_shape_continuous <- function(...) { 38 | cli::cli_abort(c( 39 | "A continuous variable cannot be mapped to the {.field edge_shape} aesthetic", 40 | "i" = "choose a different aesthetic or use {.fn scale_edge_shape_binned}" 41 | )) 42 | } 43 | #' @rdname scale_edge_shape 44 | #' 45 | #' @export 46 | scale_edge_shape_binned <- function(..., solid = TRUE) { 47 | sc <- scale_shape_binned(..., solid = solid) 48 | sc$aesthetics <- 'edge_shape' 49 | sc 50 | } 51 | #' @rdname scale_edge_shape 52 | #' 53 | #' @inheritParams ggplot2::scale_shape_manual 54 | #' 55 | #' @export 56 | scale_edge_shape_manual <- function(..., values, breaks = waiver(), na.value = NA) { 57 | sc <- scale_shape_manual(..., values = values, breaks = breaks, na.value = na.value) 58 | sc$aesthetics <- 'edge_shape' 59 | sc 60 | } 61 | #' @rdname scale_edge_shape 62 | #' 63 | #' @inheritParams ggplot2::scale_shape_identity 64 | #' 65 | #' @importFrom scales identity_pal 66 | #' @export 67 | scale_edge_shape_identity <- function(..., guide = 'none') { 68 | sc <- scale_shape_identity(..., guide = guide) 69 | sc$aesthetics <- 'edge_shape' 70 | sc 71 | } 72 | -------------------------------------------------------------------------------- /R/scale_edge_width.R: -------------------------------------------------------------------------------- 1 | #' Edge width scales 2 | #' 3 | #' This set of scales defines width scales for edge geoms. Of all the new edge 4 | #' scales defined in ggraph, this is the only one not having an equivalent in 5 | #' ggplot2. In essence it mimics the use of size in 6 | #' [ggplot2::geom_line()] and related. As almost all edge 7 | #' representations are lines of some sort, edge_width will be used much more 8 | #' often than edge_size. It is not necessary to spell out that it is an edge 9 | #' scale as the geom knows if it is drawing an edge. Just write `width` and 10 | #' not `edge_width` in the call to geoms. 11 | #' 12 | #' @return A ggproto object inheriting from `Scale` 13 | #' 14 | #' @family scale_edge_* 15 | #' 16 | #' @name scale_edge_width 17 | #' @rdname scale_edge_width 18 | #' 19 | NULL 20 | 21 | #' @rdname scale_edge_width 22 | #' 23 | #' @inheritParams ggplot2::scale_size_continuous 24 | #' 25 | #' @export 26 | scale_edge_width_continuous <- function(name = waiver(), breaks = waiver(), labels = waiver(), 27 | limits = NULL, range = c(1, 6), 28 | trans = "identity", guide = "legend") { 29 | sc <- scale_radius(name = name, breaks = breaks, labels = labels, limits = limits, 30 | range = range, trans = trans, guide = guide) 31 | sc$scale_name <- 'width_c' 32 | sc$aesthetics <- 'edge_width' 33 | sc 34 | } 35 | #' @rdname scale_edge_width 36 | #' 37 | #' @export 38 | scale_edge_width <- scale_edge_width_continuous 39 | #' @rdname scale_edge_width 40 | #' 41 | #' @inheritParams ggplot2::scale_size_discrete 42 | #' @export 43 | scale_edge_width_discrete <- function(...) { 44 | cli::cli_warn("Using {.field edge_width} for a discrete variable is not advised.") 45 | sc <- scale_size_ordinal(...) 46 | sc$scale_name <- 'width_d' 47 | sc$aesthetics <- 'edge_width' 48 | sc 49 | } 50 | #' @rdname scale_edge_width 51 | #' 52 | #' @inheritParams ggplot2::scale_size_binned 53 | #' @export 54 | scale_edge_width_binned <- function(name = waiver(), breaks = waiver(), labels = waiver(), 55 | limits = NULL, range = c(1, 6), n.breaks = NULL, 56 | nice.breaks = TRUE, trans = "identity", guide = "bins") { 57 | sc <- scale_size_binned(name = name, breaks = breaks, labels = labels, limits = limits, 58 | range = range, n.breaks = n.breaks, nice.breaks = nice.breaks, 59 | trans = trans, guide = guide) 60 | sc$scale_name <- 'width_b' 61 | sc$aesthetics <- 'edge_width' 62 | sc 63 | } 64 | #' @rdname scale_edge_width 65 | #' 66 | #' @inheritParams ggplot2::scale_size_manual 67 | #' 68 | #' @export 69 | scale_edge_width_manual <- function(..., values, breaks = waiver(), na.value = NA) { 70 | sc <- scale_size_manual(..., values = values, breaks = breaks, na.value = na.value) 71 | sc$aesthetics <- 'edge_width' 72 | sc 73 | } 74 | #' @rdname scale_edge_width 75 | #' 76 | #' @inheritParams ggplot2::scale_size_identity 77 | #' 78 | #' @export 79 | scale_edge_width_identity <- function(..., guide = 'none') { 80 | sc <- scale_size_identity(..., guide = guide) 81 | sc$aesthetics <- 'edge_width' 82 | sc 83 | } 84 | -------------------------------------------------------------------------------- /R/scale_label_size.R: -------------------------------------------------------------------------------- 1 | #' Edge label size scales 2 | #' 3 | #' This set of scales defines new size scales for edge labels in order to allow 4 | #' for separate sizing of edges and their labels. 5 | #' 6 | #' @return A ggproto object inheriting from `Scale` 7 | #' 8 | #' @family scale_edge_* 9 | #' 10 | #' @name scale_label_size 11 | #' @rdname scale_label_size 12 | #' 13 | NULL 14 | 15 | #' @rdname scale_label_size 16 | #' 17 | #' @inheritParams ggplot2::scale_size_continuous 18 | #' 19 | #' @export 20 | scale_label_size_continuous <- function(name = waiver(), breaks = waiver(), labels = waiver(), 21 | limits = NULL, range = c(1, 6), 22 | trans = "identity", guide = "legend") { 23 | sc <- scale_size_continuous(name = name, breaks = breaks, labels = labels, limits = limits, 24 | range = range, trans = trans, guide = guide) 25 | sc$aesthetics <- 'label_size' 26 | sc 27 | } 28 | #' @rdname scale_label_size 29 | #' 30 | #' @export 31 | scale_label_size <- scale_label_size_continuous 32 | #' @rdname scale_label_size 33 | #' 34 | #' @inheritParams ggplot2::scale_size_discrete 35 | #' 36 | #' @export 37 | scale_label_size_discrete <- function(...) { 38 | cli::cli_warn("Using {.field label_size} for a discrete variable is not advised.") 39 | sc <- scale_size_ordinal(...) 40 | sc$aesthetics <- 'label_size' 41 | sc 42 | } 43 | #' @rdname scale_label_size 44 | #' 45 | #' @inheritParams ggplot2::scale_size_binned 46 | #' @export 47 | scale_label_size_binned <- function(name = waiver(), breaks = waiver(), labels = waiver(), 48 | limits = NULL, range = c(1, 6), n.breaks = NULL, 49 | nice.breaks = TRUE, trans = "identity", guide = "bins") { 50 | sc <- scale_size_binned(name = name, breaks = breaks, labels = labels, limits = limits, 51 | range = range, n.breaks = n.breaks, nice.breaks = nice.breaks, 52 | trans = trans, guide = guide) 53 | sc$aesthetics <- 'label_size' 54 | sc 55 | } 56 | #' @rdname scale_label_size 57 | #' 58 | #' @inheritParams ggplot2::scale_size_manual 59 | #' 60 | #' @export 61 | scale_label_size_manual <- function(..., values, breaks = waiver(), na.value = NA) { 62 | sc <- scale_size_manual(..., values = values, breaks = breaks, na.value = na.value) 63 | sc$aesthetics <- 'label_size' 64 | sc 65 | } 66 | #' @rdname scale_label_size 67 | #' 68 | #' @inheritParams ggplot2::scale_size_identity 69 | #' 70 | #' @importFrom scales identity_pal 71 | #' @export 72 | scale_label_size_identity <- function(..., guide = 'none') { 73 | sc <- scale_size_identity(..., guide = guide) 74 | sc$aesthetics <- 'label_size' 75 | sc 76 | } 77 | -------------------------------------------------------------------------------- /R/textAlong.R: -------------------------------------------------------------------------------- 1 | textAlongGrob <- function(label, x = unit(0.5, 'npc'), y = unit(0.5, 'npc'), 2 | just = 'centre', hjust = NULL, vjust = NULL, rot = 0, 3 | check.overlap = FALSE, rot.type = 'rot', x0 = 0, 4 | y0 = 0, x1 = 0, y1 = 0, force.rot = TRUE, dodge = NULL, 5 | push = NULL, 6 | default.units = 'npc', name = NULL, gp = gpar(), 7 | vp = NULL) { 8 | if (!is.unit(x)) { 9 | x <- unit(x, default.units) 10 | } 11 | if (!is.unit(y)) { 12 | y <- unit(y, default.units) 13 | } 14 | if (rot.type == 'rot') { 15 | textGrob( 16 | label = label, x = x, y = y, just = just, hjust = hjust, 17 | vjust = vjust, rot = rot, check.overlap = check.overlap, 18 | default.units = default.units, name = name, gp = gp, vp = vp 19 | ) 20 | } else { 21 | if (!rot.type %in% c('along', 'across')) { 22 | cli::cli_abort('{.arg rot.type} must be either {.val rot}, {.val along), or {.val across}') 23 | } 24 | if (!is.unit(x0)) { 25 | x0 <- unit(x0, default.units) 26 | } 27 | if (!is.unit(y0)) { 28 | y0 <- unit(y0, default.units) 29 | } 30 | if (!is.unit(x1)) { 31 | x1 <- unit(x1, default.units) 32 | } 33 | if (!is.unit(y1)) { 34 | y1 <- unit(y1, default.units) 35 | } 36 | grob( 37 | label = label, x = x, y = y, just = just, hjust = hjust, 38 | vjust = vjust, rot.type = rot.type, x0 = x0, y0 = y0, x1 = x1, 39 | y1 = y1, force.rot = force.rot, dodge = dodge, push = push, 40 | check.overlap = check.overlap, name = name, gp = gp, vp = vp, 41 | cl = 'textalong' 42 | ) 43 | } 44 | } 45 | #' Text angled according to line 46 | #' 47 | #' This function takes care of recalculating the angle of the text as the device 48 | #' size changes 49 | #' 50 | #' @importFrom grid makeContent 51 | #' @export 52 | #' @keywords internal 53 | makeContent.textalong <- function(x) { 54 | x0 <- convertX(x$x0, 'mm', TRUE) 55 | y0 <- convertY(x$y0, 'mm', TRUE) 56 | x1 <- convertX(x$x1, 'mm', TRUE) 57 | y1 <- convertY(x$y1, 'mm', TRUE) 58 | xpos <- convertX(x$x, 'mm', TRUE) 59 | ypos <- convertY(x$y, 'mm', TRUE) 60 | angle <- edge_angle(x0, y0, x1, y1) 61 | if (x$rot.type == 'across') { 62 | angle <- angle - 90 63 | } 64 | if (!is.null(x$dodge)) { 65 | dodge <- convertHeight(x$dodge, 'mm', TRUE) 66 | dodge_angle <- (angle + 90) / 360 * 2 * pi 67 | dodge_x <- cos(dodge_angle) * dodge 68 | dodge_y <- sin(dodge_angle) * dodge 69 | xpos <- xpos + dodge_x 70 | ypos <- ypos + dodge_y 71 | } 72 | if (!is.null(x$push)) { 73 | push <- convertHeight(x$push, 'mm', TRUE) 74 | push_angle <- angle / 360 * 2 * pi 75 | push_x <- cos(push_angle) * push 76 | push_y <- sin(push_angle) * push 77 | xpos <- xpos + push_x 78 | ypos <- ypos + push_y 79 | } 80 | if (x$force.rot) { 81 | fix <- angle > 90 & angle < 270 82 | angle[fix] <- angle[fix] + 180 83 | } 84 | grob( 85 | label = x$label, x = unit(xpos, 'mm'), y = unit(ypos, 'mm'), 86 | just = x$just, hjust = x$hjust, vjust = x$vjust, rot = angle, 87 | check.overlap = x$check.overlap, name = x$name, gp = x$gp, vp = x$vp, 88 | cl = 'text' 89 | ) 90 | } 91 | -------------------------------------------------------------------------------- /R/zzz.R: -------------------------------------------------------------------------------- 1 | .onLoad <- function(...) { 2 | register_s3_method("gganimate", "layer_type", "GeomEdgePath") 3 | 4 | invisible() 5 | } 6 | 7 | register_s3_method <- function(pkg, generic, class, fun = NULL) { 8 | stopifnot(is.character(pkg), length(pkg) == 1) 9 | stopifnot(is.character(generic), length(generic) == 1) 10 | stopifnot(is.character(class), length(class) == 1) 11 | 12 | if (is.null(fun)) { 13 | fun <- get(paste0(generic, ".", class), envir = parent.frame()) 14 | } else { 15 | stopifnot(is.function(fun)) 16 | } 17 | 18 | if (pkg %in% loadedNamespaces()) { 19 | registerS3method(generic, class, fun, envir = asNamespace(pkg)) 20 | } 21 | 22 | # Always register hook in case package is later unloaded & reloaded 23 | setHook( 24 | packageEvent(pkg, "onLoad"), 25 | function(...) { 26 | registerS3method(generic, class, fun, envir = asNamespace(pkg)) 27 | } 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /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 | This is a small patch release rolling back use of native pipe to continue 2 | supporting older versions of R 3 | -------------------------------------------------------------------------------- /data/flare.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/data/flare.rda -------------------------------------------------------------------------------- /data/highschool.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/data/highschool.rda -------------------------------------------------------------------------------- /data/whigs.rda: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/data/whigs.rda -------------------------------------------------------------------------------- /man/autograph.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/autograph.R 3 | \name{autograph} 4 | \alias{autograph} 5 | \alias{autograph.default} 6 | \title{Quickplot wrapper for networks} 7 | \usage{ 8 | autograph(graph, ...) 9 | 10 | \method{autograph}{default}( 11 | graph, 12 | ..., 13 | node_colour = NULL, 14 | edge_colour = NULL, 15 | node_size = NULL, 16 | edge_width = NULL, 17 | node_label = NULL, 18 | edge_label = NULL 19 | ) 20 | } 21 | \arguments{ 22 | \item{graph}{An object coercible to a tbl_graph} 23 | 24 | \item{...}{arguments passed on to methods} 25 | 26 | \item{node_colour, edge_colour}{Colour mapping for nodes and edges} 27 | 28 | \item{node_size, edge_width}{Size/width mapping for nodes and edges} 29 | 30 | \item{node_label, edge_label}{Label mapping for nodes and edges} 31 | } 32 | \description{ 33 | This function is intended to quickly show an overview of your network data. 34 | While it returns a ggraph object that layers etc can be added to it is 35 | limited in use and should not be used as a foundation for more complicated 36 | plots. It allows colour, labeling and sizing of nodes and edges, and the 37 | exact combination of layout and layers will depend on these as well as the 38 | features of the network. The output of this function may be fine-tuned at any 39 | release and should not be considered stable. If a plot should be reproducible 40 | it should be created manually. 41 | } 42 | \examples{ 43 | library(tidygraph) 44 | gr <- create_notable('herschel') \%>\% 45 | mutate(class = sample(letters[1:3], n(), TRUE)) \%E>\% 46 | mutate(weight = runif(n())) 47 | 48 | # Standard graph 49 | autograph(gr) 50 | 51 | # Adding node labels will cap edges 52 | autograph(gr, node_label = class) 53 | 54 | # Use tidygraph calls for mapping 55 | autograph(gr, node_size = centrality_pagerank()) 56 | 57 | # Trees are plotted as dendrograms 58 | iris_tree <- hclust(dist(iris[1:4], method = 'euclidean'), method = 'ward.D2') 59 | autograph(iris_tree) 60 | 61 | } 62 | -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/man/figures/README-unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /man/figures/lifecycle-archived.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: archived 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | archived 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-defunct.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: defunct 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | defunct 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-experimental.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: experimental 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | experimental 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-maturing.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: maturing 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | maturing 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-questioning.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: questioning 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | questioning 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-soft-deprecated.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: soft-deprecated 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | soft-deprecated 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/lifecycle-stable.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: stable 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | lifecycle 21 | 22 | 25 | 26 | stable 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /man/figures/lifecycle-superseded.svg: -------------------------------------------------------------------------------- 1 | 2 | lifecycle: superseded 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | lifecycle 18 | 19 | superseded 20 | 21 | 22 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/man/figures/logo.png -------------------------------------------------------------------------------- /man/flare.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_flare.R 3 | \docType{data} 4 | \name{flare} 5 | \alias{flare} 6 | \title{The class hierarchy of the flare visualization library} 7 | \format{ 8 | A list of three data.frames describing the software structure of 9 | flare: 10 | \describe{ 11 | \item{edges}{This data.frame maps the hierarchical structure of the class 12 | hierarchy as an edgelist, with the class in \code{from} being the superclass 13 | of the class in \code{to}.} 14 | \item{vertices}{This data.frame gives additional information on the classes. 15 | It contains the full name, size and short name of each class.} 16 | \item{imports}{This data.frame contains the class imports for each class 17 | implementation. The \code{from} column gives the importing class and the 18 | \code{to} column gives the import.} 19 | } 20 | } 21 | \source{ 22 | The data have been adapted from the JSON downloaded from 23 | \url{https://gist.github.com/mbostock/1044242#file-readme-flare-imports-json} 24 | courtesy of Mike Bostock. The Flare framework is the work of the 25 | \href{http://vis.berkeley.edu/}{UC Berkeley Visualization Lab}. 26 | } 27 | \usage{ 28 | flare 29 | } 30 | \description{ 31 | This dataset contains the graph that describes the class hierarchy for the 32 | \href{https://blokt.com/tool/prefuse-flare}{Flare} ActionScript visualization library. It 33 | contains both the class hierarchy as well as the import connections between 34 | classes. This dataset has been used extensively in the D3.js documentation 35 | and examples and are included here to make it easy to redo the examples in 36 | ggraph. 37 | } 38 | \keyword{datasets} 39 | -------------------------------------------------------------------------------- /man/geom_node_circle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geom_node_circle.R 3 | \name{geom_node_circle} 4 | \alias{geom_node_circle} 5 | \title{Show nodes as circles} 6 | \usage{ 7 | geom_node_circle( 8 | mapping = NULL, 9 | data = NULL, 10 | position = "identity", 11 | show.legend = NA, 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{ggplot2::aes()}} 17 | or \code{\link[ggplot2:aes_]{ggplot2::aes_()}}. By default x and y are mapped to x0 and y0 in 18 | the node data.} 19 | 20 | \item{data}{The data to be displayed in this layer. There are three 21 | options: 22 | 23 | If \code{NULL}, the default, the data is inherited from the plot 24 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 25 | 26 | A \code{data.frame}, or other object, will override the plot 27 | data. All objects will be fortified to produce a data frame. See 28 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 29 | 30 | A \code{function} will be called with a single argument, 31 | the plot data. The return value must be a \code{data.frame}, and 32 | will be used as the layer data. A \code{function} can be created 33 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 34 | 35 | \item{position}{Position adjustment, either as a string naming the adjustment 36 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 37 | position adjustment function. Use the latter if you need to change the 38 | settings of the adjustment.} 39 | 40 | \item{show.legend}{logical. Should this layer be included in the legends? 41 | \code{NA}, the default, includes if any aesthetics are mapped. 42 | \code{FALSE} never includes, and \code{TRUE} always includes. 43 | It can also be a named logical vector to finely select the aesthetics to 44 | display.} 45 | 46 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 47 | often aesthetics, used to set an aesthetic to a fixed value, like 48 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 49 | to the paired geom/stat.} 50 | } 51 | \description{ 52 | This geom is equivalent in functionality to \code{\link[ggforce:geom_circle]{ggforce::geom_circle()}} 53 | and allows for plotting of nodes as circles with a radius scaled by the 54 | coordinate system. Because of the geoms reliance on the coordinate system 55 | it will only produce true circles when combined with 56 | \code{\link[ggplot2:coord_fixed]{ggplot2::coord_fixed()}} 57 | } 58 | \section{Aesthetics}{ 59 | 60 | \code{geom_node_circle} understand the following aesthetics. Bold aesthetics are 61 | automatically set, but can be overwritten. 62 | \itemize{ 63 | \item \strong{x0} 64 | \item \strong{y0} 65 | \item \strong{r} 66 | \item alpha 67 | \item colour 68 | \item fill 69 | \item shape 70 | \item size 71 | \item stroke 72 | \item filter 73 | } 74 | } 75 | 76 | \examples{ 77 | require(tidygraph) 78 | gr <- tbl_graph(flare$vertices, flare$edges) 79 | ggraph(gr, 'circlepack', weight = size) + 80 | geom_node_circle() + 81 | coord_fixed() 82 | } 83 | \seealso{ 84 | Other geom_node_*: 85 | \code{\link{geom_node_arc_bar}()}, 86 | \code{\link{geom_node_point}()}, 87 | \code{\link{geom_node_range}()}, 88 | \code{\link{geom_node_sf}()}, 89 | \code{\link{geom_node_text}()}, 90 | \code{\link{geom_node_tile}()}, 91 | \code{\link{geom_node_voronoi}()} 92 | } 93 | \author{ 94 | Thomas Lin Pedersen 95 | } 96 | \concept{geom_node_*} 97 | -------------------------------------------------------------------------------- /man/geom_node_point.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geom_node_point.R 3 | \name{geom_node_point} 4 | \alias{geom_node_point} 5 | \title{Show nodes as points} 6 | \usage{ 7 | geom_node_point( 8 | mapping = NULL, 9 | data = NULL, 10 | position = "identity", 11 | show.legend = NA, 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{ggplot2::aes()}} 17 | or \code{\link[ggplot2:aes_]{ggplot2::aes_()}}. By default x and y are mapped to x and y in 18 | the node data.} 19 | 20 | \item{data}{The data to be displayed in this layer. There are three 21 | options: 22 | 23 | If \code{NULL}, the default, the data is inherited from the plot 24 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 25 | 26 | A \code{data.frame}, or other object, will override the plot 27 | data. All objects will be fortified to produce a data frame. See 28 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 29 | 30 | A \code{function} will be called with a single argument, 31 | the plot data. The return value must be a \code{data.frame}, and 32 | will be used as the layer data. A \code{function} can be created 33 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 34 | 35 | \item{position}{Position adjustment, either as a string naming the adjustment 36 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 37 | position adjustment function. Use the latter if you need to change the 38 | settings of the adjustment.} 39 | 40 | \item{show.legend}{logical. Should this layer be included in the legends? 41 | \code{NA}, the default, includes if any aesthetics are mapped. 42 | \code{FALSE} never includes, and \code{TRUE} always includes. 43 | It can also be a named logical vector to finely select the aesthetics to 44 | display.} 45 | 46 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 47 | often aesthetics, used to set an aesthetic to a fixed value, like 48 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 49 | to the paired geom/stat.} 50 | } 51 | \description{ 52 | This geom is equivalent in functionality to \code{\link[ggplot2:geom_point]{ggplot2::geom_point()}} 53 | and allows for simple plotting of nodes in different shapes, colours and sizes. 54 | } 55 | \section{Aesthetics}{ 56 | 57 | \code{geom_node_point} understand the following aesthetics. Bold aesthetics are 58 | automatically set, but can be overwritten. 59 | \itemize{ 60 | \item \strong{x} 61 | \item \strong{y} 62 | \item alpha 63 | \item colour 64 | \item fill 65 | \item shape 66 | \item size 67 | \item stroke 68 | \item filter 69 | } 70 | } 71 | 72 | \examples{ 73 | require(tidygraph) 74 | gr <- create_notable('bull') \%>\% 75 | mutate(class = sample(letters[1:3], n(), replace = TRUE)) 76 | 77 | ggraph(gr, 'stress') + geom_node_point() 78 | } 79 | \seealso{ 80 | Other geom_node_*: 81 | \code{\link{geom_node_arc_bar}()}, 82 | \code{\link{geom_node_circle}()}, 83 | \code{\link{geom_node_range}()}, 84 | \code{\link{geom_node_sf}()}, 85 | \code{\link{geom_node_text}()}, 86 | \code{\link{geom_node_tile}()}, 87 | \code{\link{geom_node_voronoi}()} 88 | } 89 | \author{ 90 | Thomas Lin Pedersen 91 | } 92 | \concept{geom_node_*} 93 | -------------------------------------------------------------------------------- /man/geom_node_range.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geom_node_range.R 3 | \name{geom_node_range} 4 | \alias{geom_node_range} 5 | \title{Show nodes as a line spanning a horizontal range} 6 | \usage{ 7 | geom_node_range( 8 | mapping = NULL, 9 | data = NULL, 10 | position = "identity", 11 | show.legend = NA, 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{ggplot2::aes()}} 17 | or \code{\link[ggplot2:aes_]{ggplot2::aes_()}}. By default x is mapped to xmin, xend is mapped to xmax 18 | and y and yend are mapped to y in the node data.} 19 | 20 | \item{data}{The data to be displayed in this layer. There are three 21 | options: 22 | 23 | If \code{NULL}, the default, the data is inherited from the plot 24 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 25 | 26 | A \code{data.frame}, or other object, will override the plot 27 | data. All objects will be fortified to produce a data frame. See 28 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 29 | 30 | A \code{function} will be called with a single argument, 31 | the plot data. The return value must be a \code{data.frame}, and 32 | will be used as the layer data. A \code{function} can be created 33 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 34 | 35 | \item{position}{Position adjustment, either as a string naming the adjustment 36 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 37 | position adjustment function. Use the latter if you need to change the 38 | settings of the adjustment.} 39 | 40 | \item{show.legend}{logical. Should this layer be included in the legends? 41 | \code{NA}, the default, includes if any aesthetics are mapped. 42 | \code{FALSE} never includes, and \code{TRUE} always includes. 43 | It can also be a named logical vector to finely select the aesthetics to 44 | display.} 45 | 46 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 47 | often aesthetics, used to set an aesthetic to a fixed value, like 48 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 49 | to the paired geom/stat.} 50 | } 51 | \description{ 52 | This geom is most useful together with the \link[=layout_tbl_graph_fabric]{fabric} 53 | layout for showing the horizontal span of each node. 54 | } 55 | \section{Aesthetics}{ 56 | 57 | \code{geom_node_point} understand the following aesthetics. Bold aesthetics are 58 | automatically set, but can be overwritten. 59 | \itemize{ 60 | \item \strong{x} 61 | \item \strong{xend} 62 | \item \strong{y} 63 | \item \strong{yend} 64 | \item alpha 65 | \item colour 66 | \item linetype 67 | \item size 68 | \item filter 69 | } 70 | } 71 | 72 | \examples{ 73 | require(tidygraph) 74 | gr <- as_tbl_graph(highschool) 75 | 76 | ggraph(gr, layout = 'fabric') + 77 | geom_node_range() 78 | } 79 | \seealso{ 80 | Other geom_node_*: 81 | \code{\link{geom_node_arc_bar}()}, 82 | \code{\link{geom_node_circle}()}, 83 | \code{\link{geom_node_point}()}, 84 | \code{\link{geom_node_sf}()}, 85 | \code{\link{geom_node_text}()}, 86 | \code{\link{geom_node_tile}()}, 87 | \code{\link{geom_node_voronoi}()} 88 | } 89 | \author{ 90 | Thomas Lin Pedersen 91 | } 92 | \concept{geom_node_*} 93 | -------------------------------------------------------------------------------- /man/geom_node_sf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geom_node_sf.R 3 | \name{geom_node_sf} 4 | \alias{geom_node_sf} 5 | \title{Show nodes as POINTs in geographical space} 6 | \usage{ 7 | geom_node_sf( 8 | mapping = NULL, 9 | data = get_sf_nodes(), 10 | position = "identity", 11 | show.legend = NA, 12 | ... 13 | ) 14 | } 15 | \arguments{ 16 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{ggplot2::aes()}} 17 | or \code{\link[ggplot2:aes_]{ggplot2::aes_()}}. By default geometry is mapped to the geometry in 18 | the node data.} 19 | 20 | \item{data}{The data to be displayed in this layer. There are three 21 | options: 22 | 23 | If \code{NULL}, the default, the data is inherited from the plot 24 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}. 25 | 26 | A \code{data.frame}, or other object, will override the plot 27 | data. All objects will be fortified to produce a data frame. See 28 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created. 29 | 30 | A \code{function} will be called with a single argument, 31 | the plot data. The return value must be a \code{data.frame}, and 32 | will be used as the layer data. A \code{function} can be created 33 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).} 34 | 35 | \item{position}{Position adjustment, either as a string naming the adjustment 36 | (e.g. \code{"jitter"} to use \code{position_jitter}), or the result of a call to a 37 | position adjustment function. Use the latter if you need to change the 38 | settings of the adjustment.} 39 | 40 | \item{show.legend}{logical. Should this layer be included in the legends? 41 | \code{NA}, the default, includes if any aesthetics are mapped. 42 | \code{FALSE} never includes, and \code{TRUE} always includes. 43 | 44 | You can also set this to one of "polygon", "line", and "point" to 45 | override the default legend.} 46 | 47 | \item{...}{Other arguments passed on to \code{\link[ggplot2:layer]{layer()}}. These are 48 | often aesthetics, used to set an aesthetic to a fixed value, like 49 | \code{colour = "red"} or \code{size = 3}. They may also be parameters 50 | to the paired geom/stat.} 51 | } 52 | \description{ 53 | This geom is equivalent in functionality to \code{\link[ggplot2:ggsf]{ggplot2::geom_sf()}} for \code{POINT} 54 | geometries and allows for plotting of nodes in their geographical space in 55 | different shapes, colours and sizes. 56 | } 57 | \section{Aesthetics}{ 58 | 59 | \code{geom_node_sf} understand the following aesthetics. 60 | \itemize{ 61 | \item alpha 62 | \item colour 63 | \item shape 64 | \item size 65 | \item filter 66 | } 67 | } 68 | 69 | \examples{ 70 | library(tidygraph) 71 | 72 | if (require("sfnetworks", quietly = TRUE)) { 73 | gr <- sfnetworks::as_sfnetwork(roxel) 74 | ggraph(gr, 'sf') + 75 | geom_node_sf(aes(color = centrality_betweenness())) 76 | } 77 | 78 | } 79 | \seealso{ 80 | Other geom_node_*: 81 | \code{\link{geom_node_arc_bar}()}, 82 | \code{\link{geom_node_circle}()}, 83 | \code{\link{geom_node_point}()}, 84 | \code{\link{geom_node_range}()}, 85 | \code{\link{geom_node_text}()}, 86 | \code{\link{geom_node_tile}()}, 87 | \code{\link{geom_node_voronoi}()} 88 | } 89 | \author{ 90 | Lorena Abad 91 | } 92 | \concept{geom_node_*} 93 | -------------------------------------------------------------------------------- /man/geometry.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geometry.R 3 | \name{geometry} 4 | \alias{geometry} 5 | \alias{circle} 6 | \alias{square} 7 | \alias{ellipsis} 8 | \alias{rectangle} 9 | \alias{label_rect} 10 | \alias{is.geometry} 11 | \title{Define simple shapes for line capping} 12 | \usage{ 13 | geometry( 14 | type = "circle", 15 | width = 1, 16 | height = width, 17 | width_unit = "cm", 18 | height_unit = width_unit 19 | ) 20 | 21 | circle(radius = 1, unit = "cm") 22 | 23 | square(length = 1, unit = "cm") 24 | 25 | ellipsis(a = 1, b = 1, a_unit = "cm", b_unit = a_unit) 26 | 27 | rectangle(width = 1, height = 1, width_unit = "cm", height_unit = width_unit) 28 | 29 | label_rect(label, padding = margin(1, 1, 1.5, 1, "mm"), ...) 30 | 31 | is.geometry(x) 32 | } 33 | \arguments{ 34 | \item{type}{The type of geometry to use. Currently \code{'circle'} and 35 | \code{'rect'} is supported.} 36 | 37 | \item{width, height, length, radius, a, b}{The dimensions of the shape.} 38 | 39 | \item{unit, width_unit, height_unit, a_unit, b_unit}{The unit for the numbers 40 | given.} 41 | 42 | \item{label}{The text to be enclosed} 43 | 44 | \item{padding}{extra size to be added around the text using the 45 | \code{\link[ggplot2:element]{ggplot2::margin()}} function} 46 | 47 | \item{...}{Passed on to \code{\link[grid:gpar]{grid::gpar()}}} 48 | 49 | \item{x}{An object to test for geometry inheritance} 50 | } 51 | \value{ 52 | A geometry object encoding the specified shape. 53 | } 54 | \description{ 55 | This set of functions makes it easy to define shapes at the terminal points 56 | of edges that are used to shorten the edges. The shapes themselves are not 57 | drawn, but the edges will end at the boundary of the shape rather than at 58 | the node position. This is especially relevant when drawing arrows at the 59 | edges as the arrows will be partly obscured by the node unless the edge is 60 | shortened. Edge shortening is dynamic and will update as the plot is resized, 61 | making sure that the capping remains at an absolute distance to the end 62 | point. 63 | } 64 | \details{ 65 | \code{geometry} is the base constructor, while the rest are helpers to save 66 | typing. \code{circle} creates circles width a given radius, \code{square} 67 | creates squares at a given side length, \code{ellipsis} creates ellipses with 68 | given a and b values (width and height radii), and \code{rectangle} makes 69 | rectangles of a given width and height. label_rect is a helper that, given 70 | a list of strings and potentially formatting options creates a rectangle that 71 | encloses the string. 72 | } 73 | \examples{ 74 | geometry(c('circle', 'rect', 'rect'), 1:3, 3:1) 75 | 76 | circle(1:4, 'mm') 77 | 78 | label_rect(c('some', 'different', 'words'), fontsize = 18) 79 | } 80 | -------------------------------------------------------------------------------- /man/get_con.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/connections.R 3 | \name{get_con} 4 | \alias{get_con} 5 | \title{Create a connection extractor function} 6 | \usage{ 7 | get_con( 8 | from = integer(), 9 | to = integer(), 10 | paths = NULL, 11 | ..., 12 | weight = NULL, 13 | mode = "all" 14 | ) 15 | } 16 | \arguments{ 17 | \item{from, to}{The index of the start and end nodes for the connections} 18 | 19 | \item{paths}{A list of integer vectors giving the index of nodes defining 20 | connections} 21 | 22 | \item{...}{Additional information to be added to the final data output. 23 | Accepts expressions that will be evaluated on the node data in it's 24 | original order (irrespective of any reordering by the layout)} 25 | 26 | \item{weight}{An expression to be evaluated on the edge data to provide 27 | weights for the shortest path calculations} 28 | 29 | \item{mode}{Character constant, gives whether the shortest paths to or from 30 | the given vertices should be calculated for directed graphs. If \code{out} 31 | then the shortest paths \emph{from} the vertex, if \verb{in} then \emph{to} 32 | it will be considered. If \code{all}, the default, then the corresponding 33 | undirected graph will be used, i.e. not directed paths are searched. This 34 | argument is ignored for undirected graphs.} 35 | } 36 | \value{ 37 | A function that takes a layout_ggraph object and returns the given 38 | connections 39 | } 40 | \description{ 41 | Connections within the ggraph terminology are links between nodes that are 42 | not part of the network structure itself. In that sense connections do not 43 | affect the layout calculation in any way and will not be drawn by the 44 | standard \verb{geom_edge_*} functions. A connection does not need to only be 45 | defined by a start and end node, but can include intermediary nodes. 46 | \code{get_con} helps in creating connection data by letting you specify start 47 | and end nodes and automatically finds the shortest path within the graph 48 | structure that connects the given points. If this is not what is needed it is 49 | also possible to supply a list of vectors giving node indices that define a 50 | connection. 51 | } 52 | \seealso{ 53 | Other extractors: 54 | \code{\link{get_edges}()}, 55 | \code{\link{get_sf_nodes}()} 56 | } 57 | \concept{extractors} 58 | -------------------------------------------------------------------------------- /man/get_nodes.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geom_node_sf.R, R/nodes.R 3 | \name{get_sf_nodes} 4 | \alias{get_sf_nodes} 5 | \alias{get_nodes} 6 | \title{Create a node extractor function} 7 | \usage{ 8 | get_sf_nodes() 9 | 10 | get_nodes(...) 11 | } 12 | \arguments{ 13 | \item{...}{Additional data that should be cbind'ed together with the node 14 | data. Accepts expressions that will be evaluated on the node data in it's 15 | original order (irrespective of any reordering by the layout)} 16 | } 17 | \value{ 18 | A data.frame with the node data as well of any additional data 19 | supplied through \code{...} 20 | } 21 | \description{ 22 | This function returns another function that can extract nodes from a 23 | ggraph_layout object. As a ggraph_layout object is essentially a data.frame 24 | of nodes it might seem useless to provide this function, but since the node 25 | data is not necessarily available until after the \code{ggraph()} call it 26 | can be beneficial to be able to add information to the node data on a 27 | per-layer basis. Unlike \code{\link[=get_edges]{get_edges()}} the use of \code{get_nodes} is not 28 | mandatory and is only required if additional data should be added to selected 29 | node layers. 30 | } 31 | \seealso{ 32 | Other extractors: 33 | \code{\link{get_con}()}, 34 | \code{\link{get_edges}()} 35 | } 36 | \concept{extractors} 37 | -------------------------------------------------------------------------------- /man/ggraph-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ggraph-package.R 3 | \docType{package} 4 | \name{ggraph-package} 5 | \alias{ggraph-package} 6 | \title{ggraph: An Implementation of Grammar of Graphics for Graphs and Networks} 7 | \description{ 8 | \if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} 9 | 10 | The grammar of graphics as implemented in ggplot2 is a poor fit for graph and network visualizations due to its reliance on tabular data input. ggraph is an extension of the ggplot2 API tailored to graph visualizations and provides the same flexible approach to building up plots layer by layer. 11 | } 12 | \seealso{ 13 | Useful links: 14 | \itemize{ 15 | \item \url{https://ggraph.data-imaginist.com} 16 | \item \url{https://github.com/thomasp85/ggraph} 17 | \item Report bugs at \url{https://github.com/thomasp85/ggraph/issues} 18 | } 19 | 20 | } 21 | \author{ 22 | \strong{Maintainer}: Thomas Lin Pedersen \email{thomasp85@gmail.com} (\href{https://orcid.org/0000-0002-5147-4711}{ORCID}) 23 | 24 | Other contributors: 25 | \itemize{ 26 | \item RStudio [copyright holder] 27 | } 28 | 29 | } 30 | \keyword{internal} 31 | -------------------------------------------------------------------------------- /man/highschool.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_highschool.R 3 | \docType{data} 4 | \name{highschool} 5 | \alias{highschool} 6 | \title{Friendship among high school boys} 7 | \format{ 8 | The graph is stored as an unnamed edgelist with a year attribute. 9 | \describe{ 10 | \item{from}{The boy answering the question} 11 | \item{to}{The boy being the answer to the question} 12 | \item{year}{The year the friendship was reported} 13 | } 14 | } 15 | \source{ 16 | Coleman, J. S. \emph{Introduction to Mathematical Sociology}. New York: Free 17 | Press, pp.450-451. 18 | } 19 | \usage{ 20 | highschool 21 | } 22 | \description{ 23 | This dataset shows the friendship among high school boys as assessed by the 24 | question: "What fellows here in school do you go around with most often?". 25 | The question was posed twice, with one year in between (1957 and 1958) and 26 | shows the evolution in friendship between the two timepoints. 27 | } 28 | \keyword{datasets} 29 | -------------------------------------------------------------------------------- /man/internal_extractors.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/connections.R, R/edges.R 3 | \name{internal_extractors} 4 | \alias{internal_extractors} 5 | \alias{collect_connections} 6 | \alias{collect_edges} 7 | \title{Internal data extractors} 8 | \usage{ 9 | collect_connections(layout, from, to, ...) 10 | 11 | collect_edges(layout) 12 | } 13 | \arguments{ 14 | \item{layout}{The layout data} 15 | 16 | \item{from, to}{A numeric vector giving the indexes of the start and end nodes} 17 | 18 | \item{...}{Additional parameters passed on to the specific method} 19 | } 20 | \description{ 21 | These functions exists for supporting different data structures. There is no 22 | need to call these directly 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_auto.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_auto.R 3 | \name{layout_tbl_graph_auto} 4 | \alias{layout_tbl_graph_auto} 5 | \title{Automatically pick a layout based on graph type} 6 | \usage{ 7 | layout_tbl_graph_auto(graph, circular, ...) 8 | } 9 | \arguments{ 10 | \item{graph}{A tbl_graph object} 11 | 12 | \item{circular}{Logical. Should the layout be transformed to a circular 13 | representation. Defaults to \code{FALSE}. Only applicable if the graph is a tree 14 | structure} 15 | 16 | \item{...}{Arguments passed on to the chosen layout} 17 | } 18 | \value{ 19 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 20 | well as any information stored as node variables in the tbl_graph object. 21 | } 22 | \description{ 23 | This function infers the layout from the graph structure and is the default 24 | when calling \code{\link[=ggraph]{ggraph()}}. If an \code{x} and \code{y} argument is passed along, the 25 | manual layout is chosen. Otherwise if the graph is either a rooted tree or a 26 | rooted forest the layout will be \code{dendrogram} if the nodes contains a height 27 | variable or \code{tree} if not. If the tree is unrooted the \code{unrooted} layout will 28 | be used. If the tree is a DAG the \code{sygiyama} layout will be used. Otherwise 29 | the \code{stress} layout will be used (or \code{sparse_tree} if the graph contains more 30 | than 2000 nodes). 31 | } 32 | \seealso{ 33 | Other layout_tbl_graph_*: 34 | \code{\link{layout_tbl_graph_backbone}()}, 35 | \code{\link{layout_tbl_graph_cactustree}()}, 36 | \code{\link{layout_tbl_graph_centrality}()}, 37 | \code{\link{layout_tbl_graph_circlepack}()}, 38 | \code{\link{layout_tbl_graph_dendrogram}()}, 39 | \code{\link{layout_tbl_graph_eigen}()}, 40 | \code{\link{layout_tbl_graph_fabric}()}, 41 | \code{\link{layout_tbl_graph_focus}()}, 42 | \code{\link{layout_tbl_graph_hive}()}, 43 | \code{\link{layout_tbl_graph_htree}()}, 44 | \code{\link{layout_tbl_graph_igraph}()}, 45 | \code{\link{layout_tbl_graph_linear}()}, 46 | \code{\link{layout_tbl_graph_manual}()}, 47 | \code{\link{layout_tbl_graph_matrix}()}, 48 | \code{\link{layout_tbl_graph_metro}()}, 49 | \code{\link{layout_tbl_graph_partition}()}, 50 | \code{\link{layout_tbl_graph_pmds}()}, 51 | \code{\link{layout_tbl_graph_sf}()}, 52 | \code{\link{layout_tbl_graph_stress}()}, 53 | \code{\link{layout_tbl_graph_treemap}()}, 54 | \code{\link{layout_tbl_graph_unrooted}()} 55 | } 56 | \concept{layout_tbl_graph_*} 57 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_backbone.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_backbone.R 3 | \name{layout_tbl_graph_backbone} 4 | \alias{layout_tbl_graph_backbone} 5 | \title{Place node to emphasize group structure} 6 | \usage{ 7 | layout_tbl_graph_backbone(graph, keep = 0.2, circular = FALSE) 8 | } 9 | \arguments{ 10 | \item{graph}{A tbl_graph object} 11 | 12 | \item{keep}{The fraction of edges to use for creating the backbone} 13 | 14 | \item{circular}{ignored} 15 | } 16 | \value{ 17 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 18 | well as any information stored as node variables in the tbl_graph object. 19 | Further an edge attribute called \code{backbone} is added giving whether the edge 20 | was selected as backbone. 21 | } 22 | \description{ 23 | This layout is optimised for drawing small-world types of graphs often found 24 | in social networks, where distinct groups are still highly connected to the 25 | remaining graph. Typical layouts struggle with this as they attempt to 26 | minimise the edge length of all edges equally. The backbone layout is based 27 | on weighing edges based on how well they hold together communities. The end 28 | result is that communities tend to stick together despite high 29 | interconnectivity. 30 | } 31 | \references{ 32 | Nocaj, A., Ortmann, M., & Brandes, U. (2015). \emph{Untangling the hairballs of 33 | multi-centered, small-world online social media networks.} Journal of Graph 34 | Algorithms and Applications: JGAA, 19(2), 595-618. 35 | } 36 | \seealso{ 37 | Other layout_tbl_graph_*: 38 | \code{\link{layout_tbl_graph_auto}()}, 39 | \code{\link{layout_tbl_graph_cactustree}()}, 40 | \code{\link{layout_tbl_graph_centrality}()}, 41 | \code{\link{layout_tbl_graph_circlepack}()}, 42 | \code{\link{layout_tbl_graph_dendrogram}()}, 43 | \code{\link{layout_tbl_graph_eigen}()}, 44 | \code{\link{layout_tbl_graph_fabric}()}, 45 | \code{\link{layout_tbl_graph_focus}()}, 46 | \code{\link{layout_tbl_graph_hive}()}, 47 | \code{\link{layout_tbl_graph_htree}()}, 48 | \code{\link{layout_tbl_graph_igraph}()}, 49 | \code{\link{layout_tbl_graph_linear}()}, 50 | \code{\link{layout_tbl_graph_manual}()}, 51 | \code{\link{layout_tbl_graph_matrix}()}, 52 | \code{\link{layout_tbl_graph_metro}()}, 53 | \code{\link{layout_tbl_graph_partition}()}, 54 | \code{\link{layout_tbl_graph_pmds}()}, 55 | \code{\link{layout_tbl_graph_sf}()}, 56 | \code{\link{layout_tbl_graph_stress}()}, 57 | \code{\link{layout_tbl_graph_treemap}()}, 58 | \code{\link{layout_tbl_graph_unrooted}()} 59 | } 60 | \author{ 61 | The underlying algorithm is implemented in the graphlayouts package 62 | by David Schoch 63 | } 64 | \concept{layout_tbl_graph_*} 65 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_centrality.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_centrality.R 3 | \name{layout_tbl_graph_centrality} 4 | \alias{layout_tbl_graph_centrality} 5 | \title{Place nodes in circles according to centrality measure} 6 | \usage{ 7 | layout_tbl_graph_centrality( 8 | graph, 9 | centrality, 10 | scale = TRUE, 11 | niter = 500, 12 | tolerance = 1e-04, 13 | tseq = seq(0, 1, 0.2), 14 | group = NULL, 15 | shrink = 10, 16 | circular = FALSE 17 | ) 18 | } 19 | \arguments{ 20 | \item{graph}{A tbl_graph object} 21 | 22 | \item{centrality}{An expression evaluating to a centrality measure for the 23 | nodes. See the different \verb{centrality_*()} algorithms in tidygraph for a 24 | selection.} 25 | 26 | \item{scale}{Should the centrality measure be scaled between 0 and 100} 27 | 28 | \item{niter}{number of iterations during stress optimization} 29 | 30 | \item{tolerance}{stopping criterion for stress optimization} 31 | 32 | \item{tseq}{Transitioning steps} 33 | 34 | \item{group}{An expression evaluating to a grouping of the nodes. If given 35 | the layout will keep grouped nodes within an angle range of the origin} 36 | 37 | \item{shrink}{shrink the reserved angle range for a group to increase the 38 | gaps between groups} 39 | 40 | \item{circular}{ignored} 41 | } 42 | \value{ 43 | A data.frame with the columns \code{x}, \code{y}, \code{circular}, \code{centrality} as 44 | well as any information stored as node variables in the tbl_graph object. 45 | } 46 | \description{ 47 | This layout places nodes in circles with the radii relative to a given 48 | centrality measure. Under the hood it use stress majorisation to place nodes 49 | optimally given the radius constraint. 50 | } 51 | \references{ 52 | Brandes, U., & Pich, C. (2011). \emph{More flexible radial layout.} Journal of 53 | Graph Algorithms and Applications, 15(1), 157-173. 54 | } 55 | \seealso{ 56 | Other layout_tbl_graph_*: 57 | \code{\link{layout_tbl_graph_auto}()}, 58 | \code{\link{layout_tbl_graph_backbone}()}, 59 | \code{\link{layout_tbl_graph_cactustree}()}, 60 | \code{\link{layout_tbl_graph_circlepack}()}, 61 | \code{\link{layout_tbl_graph_dendrogram}()}, 62 | \code{\link{layout_tbl_graph_eigen}()}, 63 | \code{\link{layout_tbl_graph_fabric}()}, 64 | \code{\link{layout_tbl_graph_focus}()}, 65 | \code{\link{layout_tbl_graph_hive}()}, 66 | \code{\link{layout_tbl_graph_htree}()}, 67 | \code{\link{layout_tbl_graph_igraph}()}, 68 | \code{\link{layout_tbl_graph_linear}()}, 69 | \code{\link{layout_tbl_graph_manual}()}, 70 | \code{\link{layout_tbl_graph_matrix}()}, 71 | \code{\link{layout_tbl_graph_metro}()}, 72 | \code{\link{layout_tbl_graph_partition}()}, 73 | \code{\link{layout_tbl_graph_pmds}()}, 74 | \code{\link{layout_tbl_graph_sf}()}, 75 | \code{\link{layout_tbl_graph_stress}()}, 76 | \code{\link{layout_tbl_graph_treemap}()}, 77 | \code{\link{layout_tbl_graph_unrooted}()} 78 | } 79 | \author{ 80 | The underlying algorithm is implemented in the graphlayouts package 81 | by David Schoch 82 | } 83 | \concept{layout_tbl_graph_*} 84 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_dendrogram.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_dendrogram.R 3 | \name{layout_tbl_graph_dendrogram} 4 | \alias{layout_tbl_graph_dendrogram} 5 | \title{Apply a dendrogram layout to layout_tbl_graph} 6 | \usage{ 7 | layout_tbl_graph_dendrogram( 8 | graph, 9 | circular = FALSE, 10 | offset = pi/2, 11 | height = NULL, 12 | length = NULL, 13 | repel = FALSE, 14 | ratio = 1, 15 | direction = "out" 16 | ) 17 | } 18 | \arguments{ 19 | \item{graph}{A \code{tbl_graph} object} 20 | 21 | \item{circular}{Logical. Should the layout be transformed to a circular 22 | representation. Defaults to \code{FALSE}.} 23 | 24 | \item{offset}{If \code{circular = TRUE}, where should it begin. Defaults to 25 | \code{pi/2} which is equivalent to 12 o'clock.} 26 | 27 | \item{height}{The node variable holding the height of each node in the 28 | dendrogram. If \code{NULL} it will be calculated as the maximal distance to a 29 | leaf.} 30 | 31 | \item{length}{An edge parameter giving the length of each edge. The node 32 | height will be calculated from the maximal length to the root node (ignored 33 | if \code{height} does not evaluate to \code{NULL})} 34 | 35 | \item{repel}{Should leafs repel each other relative to the height of their 36 | common ancestor. Will emphasize clusters} 37 | 38 | \item{ratio}{The strength of repulsion if \code{repel = TRUE}. Higher values will 39 | give more defined clusters} 40 | 41 | \item{direction}{The direction to the leaves. Defaults to 'out'} 42 | } 43 | \value{ 44 | A data.frame with the columns \code{x}, \code{y}, \code{circular}, \code{depth} and 45 | \code{leaf} as well as any information stored as node variables on the 46 | tbl_graph 47 | } 48 | \description{ 49 | This layout mimics the \code{\link[igraph:layout_as_tree]{igraph::layout_as_tree()}} algorithm 50 | supplied by igraph, but puts all leaves at 0 and builds it up from there, 51 | instead of starting from the root and building it from there. The height of 52 | branch points are related to the maximum distance to an edge from the branch 53 | node, or read from a node variable. 54 | } 55 | \note{ 56 | This function is not intended to be used directly but by setting 57 | \code{layout = 'dendrogram'} in \code{\link[=create_layout]{create_layout()}} 58 | } 59 | \seealso{ 60 | Other layout_tbl_graph_*: 61 | \code{\link{layout_tbl_graph_auto}()}, 62 | \code{\link{layout_tbl_graph_backbone}()}, 63 | \code{\link{layout_tbl_graph_cactustree}()}, 64 | \code{\link{layout_tbl_graph_centrality}()}, 65 | \code{\link{layout_tbl_graph_circlepack}()}, 66 | \code{\link{layout_tbl_graph_eigen}()}, 67 | \code{\link{layout_tbl_graph_fabric}()}, 68 | \code{\link{layout_tbl_graph_focus}()}, 69 | \code{\link{layout_tbl_graph_hive}()}, 70 | \code{\link{layout_tbl_graph_htree}()}, 71 | \code{\link{layout_tbl_graph_igraph}()}, 72 | \code{\link{layout_tbl_graph_linear}()}, 73 | \code{\link{layout_tbl_graph_manual}()}, 74 | \code{\link{layout_tbl_graph_matrix}()}, 75 | \code{\link{layout_tbl_graph_metro}()}, 76 | \code{\link{layout_tbl_graph_partition}()}, 77 | \code{\link{layout_tbl_graph_pmds}()}, 78 | \code{\link{layout_tbl_graph_sf}()}, 79 | \code{\link{layout_tbl_graph_stress}()}, 80 | \code{\link{layout_tbl_graph_treemap}()}, 81 | \code{\link{layout_tbl_graph_unrooted}()} 82 | } 83 | \concept{layout_tbl_graph_*} 84 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_eigen.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_eigen.R 3 | \name{layout_tbl_graph_eigen} 4 | \alias{layout_tbl_graph_eigen} 5 | \title{Place nodes according to their eigenvalues} 6 | \usage{ 7 | layout_tbl_graph_eigen( 8 | graph, 9 | type = "laplacian", 10 | eigenvector = "smallest", 11 | circular = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{graph}{A tbl_graph object} 16 | 17 | \item{type}{The type of matrix to extract the eigenvectors from. Either 18 | \code{'laplacian'} or \code{'adjacency'}} 19 | 20 | \item{eigenvector}{The eigenvector to use for coordinates. Either \code{'smallest'} 21 | or \code{'largest'}} 22 | 23 | \item{circular}{ignored} 24 | } 25 | \value{ 26 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 27 | well as any information stored as node variables in the tbl_graph object. 28 | } 29 | \description{ 30 | This layout is based on the idea of spectral layouts where node coordinates 31 | are calculated directly by decomposing a matrix representation of the graph 32 | and extracting the eigenvectors. 33 | } 34 | \seealso{ 35 | Other layout_tbl_graph_*: 36 | \code{\link{layout_tbl_graph_auto}()}, 37 | \code{\link{layout_tbl_graph_backbone}()}, 38 | \code{\link{layout_tbl_graph_cactustree}()}, 39 | \code{\link{layout_tbl_graph_centrality}()}, 40 | \code{\link{layout_tbl_graph_circlepack}()}, 41 | \code{\link{layout_tbl_graph_dendrogram}()}, 42 | \code{\link{layout_tbl_graph_fabric}()}, 43 | \code{\link{layout_tbl_graph_focus}()}, 44 | \code{\link{layout_tbl_graph_hive}()}, 45 | \code{\link{layout_tbl_graph_htree}()}, 46 | \code{\link{layout_tbl_graph_igraph}()}, 47 | \code{\link{layout_tbl_graph_linear}()}, 48 | \code{\link{layout_tbl_graph_manual}()}, 49 | \code{\link{layout_tbl_graph_matrix}()}, 50 | \code{\link{layout_tbl_graph_metro}()}, 51 | \code{\link{layout_tbl_graph_partition}()}, 52 | \code{\link{layout_tbl_graph_pmds}()}, 53 | \code{\link{layout_tbl_graph_sf}()}, 54 | \code{\link{layout_tbl_graph_stress}()}, 55 | \code{\link{layout_tbl_graph_treemap}()}, 56 | \code{\link{layout_tbl_graph_unrooted}()} 57 | } 58 | \author{ 59 | The underlying algorithm is implemented in the graphlayouts package 60 | by David Schoch 61 | } 62 | \concept{layout_tbl_graph_*} 63 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_fabric.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_fabric.R 3 | \name{layout_tbl_graph_fabric} 4 | \alias{layout_tbl_graph_fabric} 5 | \alias{node_rank_fabric} 6 | \title{Create a fabric layout} 7 | \usage{ 8 | layout_tbl_graph_fabric( 9 | graph, 10 | circular = FALSE, 11 | sort.by = NULL, 12 | shadow.edges = FALSE 13 | ) 14 | 15 | node_rank_fabric() 16 | } 17 | \arguments{ 18 | \item{graph}{An \code{tbl_graph} object} 19 | 20 | \item{circular}{Ignored} 21 | 22 | \item{sort.by}{An expression providing the sorting of the nodes. If \code{NULL} 23 | the nodes will be ordered by their index in the graph.} 24 | 25 | \item{shadow.edges}{Should shadow edges be shown.} 26 | } 27 | \value{ 28 | A data.frame with the columns \code{x}, \code{xmin}, \code{xmax}, \code{y}, \code{circular} as 29 | well as any information stored as node variables in the tbl_graph object. 30 | Further, the edges of the graph will gain a \code{edge_x} variable giving the 31 | horizontal position of the edge as well as a \code{shadow_edge} variable denoting 32 | whether the edge is a shadow edge added by the layout. 33 | } 34 | \description{ 35 | This layout is a bit unusual in that it shows nodes as horizontal line ranges 36 | end edges as evenly spaced vertical spans connecting the nodes. As with the 37 | matrix layout the strength comes from better scalability but its use require 38 | some experience recognising the patterns that different connectivity features 39 | gives rise to. As with matrix layouts the ordering of nodes have huge power 40 | over the look of the plot. The \code{node_rank_fabric()} mimics the default 41 | ordering from the original BioFabric implementation, but other ranking 42 | algorithms from tidygraph can be used with the \code{sort.by} argument as well. 43 | Fabric layouts tend to become quite wide as the graph grows which is 44 | something that should be handled with care - e.g. by only zooming in on a 45 | specific region. 46 | } 47 | \references{ 48 | BioFabric website: \url{https://biofabric.systemsbiology.net} 49 | 50 | Longabaugh, William J.R. (2012). 51 | \emph{Combing the hairball with BioFabric: a new approach for visualization of large networks}. 52 | BMC Bioinformatics, 13: 275. \doi{10.1186/1471-2105-13-275} 53 | } 54 | \seealso{ 55 | Other layout_tbl_graph_*: 56 | \code{\link{layout_tbl_graph_auto}()}, 57 | \code{\link{layout_tbl_graph_backbone}()}, 58 | \code{\link{layout_tbl_graph_cactustree}()}, 59 | \code{\link{layout_tbl_graph_centrality}()}, 60 | \code{\link{layout_tbl_graph_circlepack}()}, 61 | \code{\link{layout_tbl_graph_dendrogram}()}, 62 | \code{\link{layout_tbl_graph_eigen}()}, 63 | \code{\link{layout_tbl_graph_focus}()}, 64 | \code{\link{layout_tbl_graph_hive}()}, 65 | \code{\link{layout_tbl_graph_htree}()}, 66 | \code{\link{layout_tbl_graph_igraph}()}, 67 | \code{\link{layout_tbl_graph_linear}()}, 68 | \code{\link{layout_tbl_graph_manual}()}, 69 | \code{\link{layout_tbl_graph_matrix}()}, 70 | \code{\link{layout_tbl_graph_metro}()}, 71 | \code{\link{layout_tbl_graph_partition}()}, 72 | \code{\link{layout_tbl_graph_pmds}()}, 73 | \code{\link{layout_tbl_graph_sf}()}, 74 | \code{\link{layout_tbl_graph_stress}()}, 75 | \code{\link{layout_tbl_graph_treemap}()}, 76 | \code{\link{layout_tbl_graph_unrooted}()} 77 | } 78 | \concept{layout_tbl_graph_*} 79 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_focus.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_focus.R 3 | \name{layout_tbl_graph_focus} 4 | \alias{layout_tbl_graph_focus} 5 | \title{Place nodes in circles based on distance to a specific node} 6 | \usage{ 7 | layout_tbl_graph_focus( 8 | graph, 9 | focus, 10 | weights = NULL, 11 | niter = 500, 12 | tolerance = 1e-04, 13 | group = NULL, 14 | shrink = 10, 15 | circular = TRUE 16 | ) 17 | } 18 | \arguments{ 19 | \item{graph}{a tbl_graph object} 20 | 21 | \item{focus}{An expression evaluating to a selected node. Can either be a 22 | single integer or a logical vector with a single \code{TRUE} element.} 23 | 24 | \item{weights}{An expression evaluated on the edge data to provide edge 25 | weights for the layout. Currently ignored for the sparse version} 26 | 27 | \item{niter}{number of iterations during stress optimization} 28 | 29 | \item{tolerance}{stopping criterion for stress optimization} 30 | 31 | \item{group}{An expression evaluating to a grouping of the nodes. If given 32 | the layout will keep grouped nodes within an angle range of the origin} 33 | 34 | \item{shrink}{shrink the reserved angle range for a group to increase the 35 | gaps between groups} 36 | 37 | \item{circular}{ignored} 38 | } 39 | \value{ 40 | A data.frame with the columns \code{x}, \code{y}, \code{circular}, \code{distance} as 41 | well as any information stored as node variables in the tbl_graph object. 42 | } 43 | \description{ 44 | This layout constrains node placement to a radius relative to its distance to 45 | a given node. It then uses stress majorisation to find an optimal node 46 | distribution according to this constraint. 47 | } 48 | \references{ 49 | Brandes, U., & Pich, C. (2011). \emph{More flexible radial layout.} Journal of 50 | Graph Algorithms and Applications, 15(1), 157-173. 51 | } 52 | \seealso{ 53 | Other layout_tbl_graph_*: 54 | \code{\link{layout_tbl_graph_auto}()}, 55 | \code{\link{layout_tbl_graph_backbone}()}, 56 | \code{\link{layout_tbl_graph_cactustree}()}, 57 | \code{\link{layout_tbl_graph_centrality}()}, 58 | \code{\link{layout_tbl_graph_circlepack}()}, 59 | \code{\link{layout_tbl_graph_dendrogram}()}, 60 | \code{\link{layout_tbl_graph_eigen}()}, 61 | \code{\link{layout_tbl_graph_fabric}()}, 62 | \code{\link{layout_tbl_graph_hive}()}, 63 | \code{\link{layout_tbl_graph_htree}()}, 64 | \code{\link{layout_tbl_graph_igraph}()}, 65 | \code{\link{layout_tbl_graph_linear}()}, 66 | \code{\link{layout_tbl_graph_manual}()}, 67 | \code{\link{layout_tbl_graph_matrix}()}, 68 | \code{\link{layout_tbl_graph_metro}()}, 69 | \code{\link{layout_tbl_graph_partition}()}, 70 | \code{\link{layout_tbl_graph_pmds}()}, 71 | \code{\link{layout_tbl_graph_sf}()}, 72 | \code{\link{layout_tbl_graph_stress}()}, 73 | \code{\link{layout_tbl_graph_treemap}()}, 74 | \code{\link{layout_tbl_graph_unrooted}()} 75 | } 76 | \author{ 77 | The underlying algorithm is implemented in the graphlayouts package 78 | by David Schoch 79 | } 80 | \concept{layout_tbl_graph_*} 81 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_htree.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_htree.R 3 | \name{layout_tbl_graph_htree} 4 | \alias{layout_tbl_graph_htree} 5 | \title{Layout binary trees in a fractal H formation} 6 | \usage{ 7 | layout_tbl_graph_htree( 8 | graph, 9 | sort.by = NULL, 10 | direction = "out", 11 | circular = FALSE 12 | ) 13 | } 14 | \arguments{ 15 | \item{graph}{An \code{tbl_graph} object} 16 | 17 | \item{sort.by}{The name of a node variable to sort the nodes by.} 18 | 19 | \item{direction}{The direction of the tree in the graph. \code{'out'} (default) 20 | means that parents point towards their children, while \code{'in'} means that 21 | children point towards their parent.} 22 | 23 | \item{circular}{Logical. Should the layout be transformed to a circular 24 | representation. Ignored} 25 | } 26 | \value{ 27 | A data.frame with the columns \code{x}, \code{y}, \code{leaf}, \code{depth}, \code{circular} 28 | as well as any information stored as node variables in the tbl_graph object. 29 | } 30 | \description{ 31 | This is a spac efficient layout only useful for binary trees. It is fractal 32 | and works by offsetting child nodes from their parent either horizontally or 33 | vertically depending on depth. The offset is decreased at each step by a 34 | factor of the square root of 2. 35 | } 36 | \note{ 37 | H Tree is a layout intended for trees, that is, graphs where nodes 38 | only have one parent and zero or more children. If the provided graph does 39 | not fit this format an attempt to convert it to such a format will be made. 40 | } 41 | \seealso{ 42 | Other layout_tbl_graph_*: 43 | \code{\link{layout_tbl_graph_auto}()}, 44 | \code{\link{layout_tbl_graph_backbone}()}, 45 | \code{\link{layout_tbl_graph_cactustree}()}, 46 | \code{\link{layout_tbl_graph_centrality}()}, 47 | \code{\link{layout_tbl_graph_circlepack}()}, 48 | \code{\link{layout_tbl_graph_dendrogram}()}, 49 | \code{\link{layout_tbl_graph_eigen}()}, 50 | \code{\link{layout_tbl_graph_fabric}()}, 51 | \code{\link{layout_tbl_graph_focus}()}, 52 | \code{\link{layout_tbl_graph_hive}()}, 53 | \code{\link{layout_tbl_graph_igraph}()}, 54 | \code{\link{layout_tbl_graph_linear}()}, 55 | \code{\link{layout_tbl_graph_manual}()}, 56 | \code{\link{layout_tbl_graph_matrix}()}, 57 | \code{\link{layout_tbl_graph_metro}()}, 58 | \code{\link{layout_tbl_graph_partition}()}, 59 | \code{\link{layout_tbl_graph_pmds}()}, 60 | \code{\link{layout_tbl_graph_sf}()}, 61 | \code{\link{layout_tbl_graph_stress}()}, 62 | \code{\link{layout_tbl_graph_treemap}()}, 63 | \code{\link{layout_tbl_graph_unrooted}()} 64 | } 65 | \concept{layout_tbl_graph_*} 66 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_linear.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_linear.R 3 | \name{layout_tbl_graph_linear} 4 | \alias{layout_tbl_graph_linear} 5 | \title{Place nodes on a line or circle} 6 | \usage{ 7 | layout_tbl_graph_linear( 8 | graph, 9 | circular, 10 | sort.by = NULL, 11 | use.numeric = FALSE, 12 | offset = pi/2, 13 | weight = NULL 14 | ) 15 | } 16 | \arguments{ 17 | \item{graph}{An \code{tbl_graph} object} 18 | 19 | \item{circular}{Logical. Should the layout be transformed to a circular 20 | representation. Defaults to \code{FALSE}.} 21 | 22 | \item{sort.by}{The name of a node variable to sort the nodes by.} 23 | 24 | \item{use.numeric}{Logical. Should a numeric sort.by attribute be used as the 25 | actual x-coordinates in the layout. May lead to overlapping nodes. Defaults 26 | to FALSE} 27 | 28 | \item{offset}{If \code{circular = TRUE}, where should it begin. Defaults to 29 | \code{pi/2} which is equivalent to 12 o'clock.} 30 | 31 | \item{weight}{A weight for each node. Nodes will be spread out according to 32 | their weight so that nodes with heigher weight will have more space around 33 | them. Ignored if \code{use.numeric = TRUE}} 34 | } 35 | \value{ 36 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 37 | well as any information stored as node variables in the tbl_graph object. 38 | Further, if \code{circular = FALSE} a \code{width} column and if \code{circular = TRUE} a 39 | \code{start}, \code{end}, and \code{r0} column. 40 | } 41 | \description{ 42 | This layout puts all nodes on a line, possibly sorted by a node attribute. If 43 | \code{circular = TRUE} the nodes will be laid out on the unit circle instead. 44 | In the case where the \code{sort.by} attribute is numeric, the numeric values 45 | will be used as the x-position and it is thus possible to have uneven spacing 46 | between the nodes. 47 | } 48 | \seealso{ 49 | Other layout_tbl_graph_*: 50 | \code{\link{layout_tbl_graph_auto}()}, 51 | \code{\link{layout_tbl_graph_backbone}()}, 52 | \code{\link{layout_tbl_graph_cactustree}()}, 53 | \code{\link{layout_tbl_graph_centrality}()}, 54 | \code{\link{layout_tbl_graph_circlepack}()}, 55 | \code{\link{layout_tbl_graph_dendrogram}()}, 56 | \code{\link{layout_tbl_graph_eigen}()}, 57 | \code{\link{layout_tbl_graph_fabric}()}, 58 | \code{\link{layout_tbl_graph_focus}()}, 59 | \code{\link{layout_tbl_graph_hive}()}, 60 | \code{\link{layout_tbl_graph_htree}()}, 61 | \code{\link{layout_tbl_graph_igraph}()}, 62 | \code{\link{layout_tbl_graph_manual}()}, 63 | \code{\link{layout_tbl_graph_matrix}()}, 64 | \code{\link{layout_tbl_graph_metro}()}, 65 | \code{\link{layout_tbl_graph_partition}()}, 66 | \code{\link{layout_tbl_graph_pmds}()}, 67 | \code{\link{layout_tbl_graph_sf}()}, 68 | \code{\link{layout_tbl_graph_stress}()}, 69 | \code{\link{layout_tbl_graph_treemap}()}, 70 | \code{\link{layout_tbl_graph_unrooted}()} 71 | } 72 | \concept{layout_tbl_graph_*} 73 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_manual.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_manual.R 3 | \name{layout_tbl_graph_manual} 4 | \alias{layout_tbl_graph_manual} 5 | \title{Manually specify a layout for layout_tbl_graph} 6 | \usage{ 7 | layout_tbl_graph_manual(graph, x, y, circular) 8 | } 9 | \arguments{ 10 | \item{graph}{An \code{tbl_graph} object} 11 | 12 | \item{x, y}{Expressions with the x and y positions of the nodes} 13 | 14 | \item{circular}{Ignored} 15 | } 16 | \value{ 17 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 18 | well as any information stored as node variables in the tbl_graph. 19 | } 20 | \description{ 21 | This layout function lets you pass the node positions in manually. The 22 | supplied positions must match the order of the nodes in the tbl_graph 23 | } 24 | \seealso{ 25 | Other layout_tbl_graph_*: 26 | \code{\link{layout_tbl_graph_auto}()}, 27 | \code{\link{layout_tbl_graph_backbone}()}, 28 | \code{\link{layout_tbl_graph_cactustree}()}, 29 | \code{\link{layout_tbl_graph_centrality}()}, 30 | \code{\link{layout_tbl_graph_circlepack}()}, 31 | \code{\link{layout_tbl_graph_dendrogram}()}, 32 | \code{\link{layout_tbl_graph_eigen}()}, 33 | \code{\link{layout_tbl_graph_fabric}()}, 34 | \code{\link{layout_tbl_graph_focus}()}, 35 | \code{\link{layout_tbl_graph_hive}()}, 36 | \code{\link{layout_tbl_graph_htree}()}, 37 | \code{\link{layout_tbl_graph_igraph}()}, 38 | \code{\link{layout_tbl_graph_linear}()}, 39 | \code{\link{layout_tbl_graph_matrix}()}, 40 | \code{\link{layout_tbl_graph_metro}()}, 41 | \code{\link{layout_tbl_graph_partition}()}, 42 | \code{\link{layout_tbl_graph_pmds}()}, 43 | \code{\link{layout_tbl_graph_sf}()}, 44 | \code{\link{layout_tbl_graph_stress}()}, 45 | \code{\link{layout_tbl_graph_treemap}()}, 46 | \code{\link{layout_tbl_graph_unrooted}()} 47 | } 48 | \concept{layout_tbl_graph_*} 49 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_matrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_matrix.R 3 | \name{layout_tbl_graph_matrix} 4 | \alias{layout_tbl_graph_matrix} 5 | \title{Place nodes on a diagonal} 6 | \usage{ 7 | layout_tbl_graph_matrix(graph, circular = FALSE, sort.by = NULL) 8 | } 9 | \arguments{ 10 | \item{graph}{An \code{tbl_graph} object} 11 | 12 | \item{circular}{Ignored} 13 | 14 | \item{sort.by}{An expression providing the sorting of the nodes. If \code{NULL} 15 | the nodes will be ordered by their index in the graph.} 16 | } 17 | \value{ 18 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 19 | well as any information stored as node variables in the tbl_graph object. 20 | } 21 | \description{ 22 | This layout puts all nodes on a diagonal, thus preparing the layout for use 23 | with \code{\link[=geom_edge_point]{geom_edge_point()}} resulting in a matrix layout. While matrix 24 | layouts excel in scalability, the interpretation of the visual is very 25 | dependent on the sorting of the nodes. Different sorting algorithms have been 26 | implemented in \code{tidygraph} and these can be used directly. Behrisch 27 | \emph{et al.} (2016) have provided a nice overview of some of the different 28 | sorting algorithms and what insight they might bring, along with a rundown of 29 | different patterns to look out for. 30 | } 31 | \references{ 32 | Behrisch, M., Bach, B., Riche, N. H., Schreck, T., Fekete, J.-D. (2016). 33 | \emph{Matrix Reordering Methods for Table and Network Visualization}. 34 | Computer Graphics Forum, 35: 693–716. \doi{10.1111/cgf.12935} 35 | } 36 | \seealso{ 37 | Other layout_tbl_graph_*: 38 | \code{\link{layout_tbl_graph_auto}()}, 39 | \code{\link{layout_tbl_graph_backbone}()}, 40 | \code{\link{layout_tbl_graph_cactustree}()}, 41 | \code{\link{layout_tbl_graph_centrality}()}, 42 | \code{\link{layout_tbl_graph_circlepack}()}, 43 | \code{\link{layout_tbl_graph_dendrogram}()}, 44 | \code{\link{layout_tbl_graph_eigen}()}, 45 | \code{\link{layout_tbl_graph_fabric}()}, 46 | \code{\link{layout_tbl_graph_focus}()}, 47 | \code{\link{layout_tbl_graph_hive}()}, 48 | \code{\link{layout_tbl_graph_htree}()}, 49 | \code{\link{layout_tbl_graph_igraph}()}, 50 | \code{\link{layout_tbl_graph_linear}()}, 51 | \code{\link{layout_tbl_graph_manual}()}, 52 | \code{\link{layout_tbl_graph_metro}()}, 53 | \code{\link{layout_tbl_graph_partition}()}, 54 | \code{\link{layout_tbl_graph_pmds}()}, 55 | \code{\link{layout_tbl_graph_sf}()}, 56 | \code{\link{layout_tbl_graph_stress}()}, 57 | \code{\link{layout_tbl_graph_treemap}()}, 58 | \code{\link{layout_tbl_graph_unrooted}()} 59 | } 60 | \concept{layout_tbl_graph_*} 61 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_pmds.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_pmds.R 3 | \name{layout_tbl_graph_pmds} 4 | \alias{layout_tbl_graph_pmds} 5 | \title{Place nodes based on a multidimensional scaling of a set of pivot nodes} 6 | \usage{ 7 | layout_tbl_graph_pmds(graph, pivots, weights = NULL, circular = FALSE) 8 | } 9 | \arguments{ 10 | \item{graph}{A tbl_graph object} 11 | 12 | \item{pivots}{The number of pivot nodes} 13 | 14 | \item{weights}{An expression evaluated on the edge data to provide edge 15 | weights for the layout. Currently ignored for the sparse version} 16 | 17 | \item{circular}{ignored} 18 | } 19 | \value{ 20 | A data.frame with the columns \code{x}, \code{y}, \code{circular} as 21 | well as any information stored as node variables in the tbl_graph object. 22 | } 23 | \description{ 24 | This layout is similar to the 'mds' layout but uses only a subset of pivot 25 | nodes for the mds calculation, making it considerably faster and thus suited 26 | for large graphs 27 | } 28 | \references{ 29 | Brandes, U. and Pich, C. (2006). \emph{Eigensolver Methods for Progressive 30 | Multidimensional Scaling of Large Data.} In International Symposium on Graph 31 | Drawing (pp. 42-53). Springer 32 | } 33 | \seealso{ 34 | Other layout_tbl_graph_*: 35 | \code{\link{layout_tbl_graph_auto}()}, 36 | \code{\link{layout_tbl_graph_backbone}()}, 37 | \code{\link{layout_tbl_graph_cactustree}()}, 38 | \code{\link{layout_tbl_graph_centrality}()}, 39 | \code{\link{layout_tbl_graph_circlepack}()}, 40 | \code{\link{layout_tbl_graph_dendrogram}()}, 41 | \code{\link{layout_tbl_graph_eigen}()}, 42 | \code{\link{layout_tbl_graph_fabric}()}, 43 | \code{\link{layout_tbl_graph_focus}()}, 44 | \code{\link{layout_tbl_graph_hive}()}, 45 | \code{\link{layout_tbl_graph_htree}()}, 46 | \code{\link{layout_tbl_graph_igraph}()}, 47 | \code{\link{layout_tbl_graph_linear}()}, 48 | \code{\link{layout_tbl_graph_manual}()}, 49 | \code{\link{layout_tbl_graph_matrix}()}, 50 | \code{\link{layout_tbl_graph_metro}()}, 51 | \code{\link{layout_tbl_graph_partition}()}, 52 | \code{\link{layout_tbl_graph_sf}()}, 53 | \code{\link{layout_tbl_graph_stress}()}, 54 | \code{\link{layout_tbl_graph_treemap}()}, 55 | \code{\link{layout_tbl_graph_unrooted}()} 56 | } 57 | \author{ 58 | The underlying algorithm is implemented in the graphlayouts package 59 | by David Schoch 60 | } 61 | \concept{layout_tbl_graph_*} 62 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_sf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_sf.R 3 | \name{layout_tbl_graph_sf} 4 | \alias{layout_tbl_graph_sf} 5 | \title{Place nodes on their geographical space} 6 | \usage{ 7 | layout_tbl_graph_sf(graph, circular = FALSE) 8 | } 9 | \arguments{ 10 | \item{graph}{An sfnetwork object} 11 | 12 | \item{circular}{ignored} 13 | } 14 | \value{ 15 | A data.frame with the columns \code{x}, \code{y}, \code{circular}. 16 | } 17 | \description{ 18 | This layout is built for objects of class \code{sfnetwork} and is meant to 19 | plot a graph on its geographical space, by extracting its X and Y coordinates 20 | } 21 | \seealso{ 22 | Other layout_tbl_graph_*: 23 | \code{\link{layout_tbl_graph_auto}()}, 24 | \code{\link{layout_tbl_graph_backbone}()}, 25 | \code{\link{layout_tbl_graph_cactustree}()}, 26 | \code{\link{layout_tbl_graph_centrality}()}, 27 | \code{\link{layout_tbl_graph_circlepack}()}, 28 | \code{\link{layout_tbl_graph_dendrogram}()}, 29 | \code{\link{layout_tbl_graph_eigen}()}, 30 | \code{\link{layout_tbl_graph_fabric}()}, 31 | \code{\link{layout_tbl_graph_focus}()}, 32 | \code{\link{layout_tbl_graph_hive}()}, 33 | \code{\link{layout_tbl_graph_htree}()}, 34 | \code{\link{layout_tbl_graph_igraph}()}, 35 | \code{\link{layout_tbl_graph_linear}()}, 36 | \code{\link{layout_tbl_graph_manual}()}, 37 | \code{\link{layout_tbl_graph_matrix}()}, 38 | \code{\link{layout_tbl_graph_metro}()}, 39 | \code{\link{layout_tbl_graph_partition}()}, 40 | \code{\link{layout_tbl_graph_pmds}()}, 41 | \code{\link{layout_tbl_graph_stress}()}, 42 | \code{\link{layout_tbl_graph_treemap}()}, 43 | \code{\link{layout_tbl_graph_unrooted}()} 44 | } 45 | \concept{layout_tbl_graph_*} 46 | -------------------------------------------------------------------------------- /man/layout_tbl_graph_unrooted.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/layout_unrooted.R 3 | \name{layout_tbl_graph_unrooted} 4 | \alias{layout_tbl_graph_unrooted} 5 | \title{Create an unrooted layout using equal-angle or equal-daylight} 6 | \usage{ 7 | layout_tbl_graph_unrooted( 8 | graph, 9 | daylight = TRUE, 10 | length = NULL, 11 | tolerance = 0.05, 12 | rotation_mod = 1, 13 | maxiter = 100, 14 | circular = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{graph}{A tbl_graph object} 19 | 20 | \item{daylight}{Should equal-daylight adjustments be made} 21 | 22 | \item{length}{An expression evaluating to the branch length of each edge} 23 | 24 | \item{tolerance}{The threshold for mean angular adjustment before terminating 25 | the daylight adjustment} 26 | 27 | \item{rotation_mod}{A modifier for the angular adjustment of each branch. Set 28 | it below 1 to let the daylight adjustment progress more slowly} 29 | 30 | \item{maxiter}{The maximum number of iterations in the the daylight 31 | adjustment} 32 | 33 | \item{circular}{ignored} 34 | } 35 | \value{ 36 | A data.frame with the columns \code{x}, \code{y}, \code{circular}, \code{leaf} as well as 37 | any information stored as node variables in the tbl_graph object. 38 | } 39 | \description{ 40 | When drawing unrooted trees the standard dendrogram layout is a bad fit as it 41 | implicitly creates a visual root node. Instead it is possible to spread the 42 | leafs out on the plane without putting any special emphasis on a particular 43 | node using an unrooted layout. The standard algorithm is the equal angle 44 | algorithm, but it can struggle with optimising the leaf distribution for 45 | large trees with very uneven branch length. The equal daylight 46 | algorithm modifies the output of the equal angle algorithm to better disperse 47 | the leaves, at the cost of higher computational cost and the possibility of 48 | edge crossings for very large unbalanced trees. For standard sized trees the 49 | daylight algorithm is far superior and not too heavy so it is the default. 50 | } 51 | \note{ 52 | Unrooted is a layout intended for undirected trees, that is, graphs with no 53 | cycles. If the provided graph does not fit this format an attempt to convert 54 | it to such a format will be made. 55 | } 56 | \references{ 57 | Felsenstein, J. (2004) \emph{Drawing Trees}, in Inferring Phylogenies. Sinauer 58 | Assoc., pp 573-584 59 | } 60 | \seealso{ 61 | Other layout_tbl_graph_*: 62 | \code{\link{layout_tbl_graph_auto}()}, 63 | \code{\link{layout_tbl_graph_backbone}()}, 64 | \code{\link{layout_tbl_graph_cactustree}()}, 65 | \code{\link{layout_tbl_graph_centrality}()}, 66 | \code{\link{layout_tbl_graph_circlepack}()}, 67 | \code{\link{layout_tbl_graph_dendrogram}()}, 68 | \code{\link{layout_tbl_graph_eigen}()}, 69 | \code{\link{layout_tbl_graph_fabric}()}, 70 | \code{\link{layout_tbl_graph_focus}()}, 71 | \code{\link{layout_tbl_graph_hive}()}, 72 | \code{\link{layout_tbl_graph_htree}()}, 73 | \code{\link{layout_tbl_graph_igraph}()}, 74 | \code{\link{layout_tbl_graph_linear}()}, 75 | \code{\link{layout_tbl_graph_manual}()}, 76 | \code{\link{layout_tbl_graph_matrix}()}, 77 | \code{\link{layout_tbl_graph_metro}()}, 78 | \code{\link{layout_tbl_graph_partition}()}, 79 | \code{\link{layout_tbl_graph_pmds}()}, 80 | \code{\link{layout_tbl_graph_sf}()}, 81 | \code{\link{layout_tbl_graph_stress}()}, 82 | \code{\link{layout_tbl_graph_treemap}()} 83 | } 84 | \concept{layout_tbl_graph_*} 85 | -------------------------------------------------------------------------------- /man/layout_to_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tbl_graph.R 3 | \name{layout_to_table} 4 | \alias{layout_to_table} 5 | \title{Convert a layout to a table} 6 | \usage{ 7 | layout_to_table(layout, graph, ...) 8 | } 9 | \arguments{ 10 | \item{layout}{A supported object} 11 | 12 | \item{graph}{A \code{tbl_graph}} 13 | 14 | \item{...}{passed on to implementations} 15 | } 16 | \value{ 17 | A valid data.frame 18 | } 19 | \description{ 20 | This generic takes care of dispatching various layout types (names, 21 | functions, tables) to their respective functions that will return a valid 22 | layout table. 23 | } 24 | \keyword{internal} 25 | -------------------------------------------------------------------------------- /man/makeContent.cappedpathgrob.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cappedPath.R 3 | \name{makeContent.cappedpathgrob} 4 | \alias{makeContent.cappedpathgrob} 5 | \title{Dynamic capping of paths} 6 | \usage{ 7 | \method{makeContent}{cappedpathgrob}(x) 8 | } 9 | \description{ 10 | This function takes care of updating which parts of the paths get removed 11 | when the device dimensions are updated. 12 | } 13 | \keyword{internal} 14 | -------------------------------------------------------------------------------- /man/makeContent.textalong.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/textAlong.R 3 | \name{makeContent.textalong} 4 | \alias{makeContent.textalong} 5 | \title{Text angled according to line} 6 | \usage{ 7 | \method{makeContent}{textalong}(x) 8 | } 9 | \description{ 10 | This function takes care of recalculating the angle of the text as the device 11 | size changes 12 | } 13 | \keyword{internal} 14 | -------------------------------------------------------------------------------- /man/node_angle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{node_angle} 4 | \alias{node_angle} 5 | \alias{edge_angle} 6 | \title{Get the angle of nodes and edges} 7 | \usage{ 8 | node_angle(x, y, degrees = TRUE, avoid_flip = TRUE) 9 | 10 | edge_angle(x, y, xend, yend, degrees = TRUE, avoid_flip = TRUE) 11 | } 12 | \arguments{ 13 | \item{x, y}{A vector of positions} 14 | 15 | \item{degrees}{Logical. Should the angle be returned in degree (\code{TRUE}) 16 | or radians (\code{FALSE}). Defaults to \code{TRUE}.} 17 | 18 | \item{avoid_flip}{Logical. Should the angle be adjusted so that text is 19 | always upside-down} 20 | 21 | \item{xend, yend}{The end position of the edge} 22 | } 23 | \value{ 24 | A vector with the angle of each node/edge 25 | } 26 | \description{ 27 | These helper functions makes it easy to calculate the angle associated with 28 | nodes and edges. For nodes the angle is defined as the angle of the vector 29 | pointing towards the node position, and is thus mainly suited for circular 30 | layouts where it can be used to calculate the angle of labels. For edges it 31 | is simply the angle of the vector describing the edge. 32 | } 33 | \examples{ 34 | require(tidygraph) 35 | flareGraph <- tbl_graph(flare$vertices, flare$edges) 36 | 37 | ggraph(flareGraph, 'dendrogram', circular = TRUE) + 38 | geom_edge_diagonal0() + 39 | geom_node_text(aes(filter = leaf, angle = node_angle(x, y), label = shortName), 40 | hjust = 'outward', size = 2 41 | ) + 42 | expand_limits(x = c(-1.3, 1.3), y = c(-1.3, 1.3)) 43 | } 44 | -------------------------------------------------------------------------------- /man/pack_circles.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pack.R 3 | \name{pack_circles} 4 | \alias{pack_circles} 5 | \title{Pack circles together} 6 | \usage{ 7 | pack_circles(areas) 8 | } 9 | \arguments{ 10 | \item{areas}{A vector of circle areas} 11 | } 12 | \value{ 13 | A matrix with two columns and the same number of rows as the length 14 | of the "areas" vector. The matrix has the following attributes added: 15 | "enclosing_radius" giving the radius of the smallest enclosing circle, and 16 | "front_chain" giving the terminating members of the front chain (see 17 | Wang \emph{et al}. 2006). 18 | } 19 | \description{ 20 | This function is a direct interface to the circle packing algorithm used by 21 | \code{\link{layout_tbl_graph_circlepack}}. It takes a vector of sizes and 22 | returns the x and y position of each circle as a two-column matrix. 23 | } 24 | \examples{ 25 | library(ggforce) 26 | sizes <- sample(10, 100, TRUE) 27 | 28 | position <- pack_circles(sizes) 29 | data <- data.frame(x = position[,1], y = position[,2], r = sqrt(sizes/pi)) 30 | 31 | ggplot() + 32 | geom_circle(aes(x0 = x, y0 = y, r = r), data = data, fill = 'steelblue') + 33 | geom_circle(aes(x0 = 0, y0 = 0, r = attr(position, 'enclosing_radius'))) + 34 | geom_polygon(aes(x = x, y = y), 35 | data = data[attr(position, 'front_chain'), ], 36 | fill = NA, 37 | colour = 'black') 38 | 39 | } 40 | \references{ 41 | Wang, W., Wang, H. H., Dai, G., & Wang, H. (2006). \emph{Visualization of 42 | large hierarchical data by circle packing}. Chi, 517-520. 43 | } 44 | -------------------------------------------------------------------------------- /man/qgraph.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/autograph.R 3 | \name{qgraph} 4 | \alias{qgraph} 5 | \title{Deprecated autograph predecessor} 6 | \usage{ 7 | qgraph(...) 8 | } 9 | \description{ 10 | Deprecated autograph predecessor 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{scale_color_viridis} 7 | \alias{scale_fill_viridis} 8 | \title{Objects exported from other packages} 9 | \keyword{internal} 10 | \description{ 11 | These objects are imported from other packages. Follow the links 12 | below to see their documentation. 13 | 14 | \describe{ 15 | \item{viridis}{\code{\link[viridis:scale_viridis]{scale_color_viridis}}, \code{\link[viridis:scale_viridis]{scale_fill_viridis}}} 16 | }} 17 | 18 | -------------------------------------------------------------------------------- /man/scale_edge_alpha.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/scale_edge_alpha.R 3 | \name{scale_edge_alpha} 4 | \alias{scale_edge_alpha} 5 | \alias{scale_edge_alpha_continuous} 6 | \alias{scale_edge_alpha_discrete} 7 | \alias{scale_edge_alpha_binned} 8 | \alias{scale_edge_alpha_manual} 9 | \alias{scale_edge_alpha_identity} 10 | \title{Edge alpha scales} 11 | \usage{ 12 | scale_edge_alpha(..., range = c(0.1, 1)) 13 | 14 | scale_edge_alpha_continuous(..., range = c(0.1, 1)) 15 | 16 | scale_edge_alpha_discrete(..., range = c(0.1, 1)) 17 | 18 | scale_edge_alpha_binned(..., range = c(0.1, 1)) 19 | 20 | scale_edge_alpha_manual(..., values, breaks = waiver(), na.value = NA) 21 | 22 | scale_edge_alpha_identity(..., guide = "none") 23 | } 24 | \arguments{ 25 | \item{...}{Other arguments passed on to \code{\link[ggplot2:continuous_scale]{continuous_scale()}}, \code{\link[ggplot2:binned_scale]{binned_scale()}}, 26 | or \code{\link[ggplot2:discrete_scale]{discrete_scale()}} as appropriate, to control name, limits, 27 | breaks, labels and so forth.} 28 | 29 | \item{range}{Output range of alpha values. Must lie between 0 and 1.} 30 | 31 | \item{values}{a set of aesthetic values to map data values to. The values 32 | will be matched in order (usually alphabetical) with the limits of the 33 | scale, or with \code{breaks} if provided. If this is a named vector, then the 34 | values will be matched based on the names instead. Data values that don't 35 | match will be given \code{na.value}.} 36 | 37 | \item{breaks}{One of: 38 | \itemize{ 39 | \item \code{NULL} for no breaks 40 | \item \code{waiver()} for the default breaks (the scale limits) 41 | \item A character vector of breaks 42 | \item A function that takes the limits as input and returns breaks 43 | as output 44 | }} 45 | 46 | \item{na.value}{The aesthetic value to use for missing (\code{NA}) values} 47 | 48 | \item{guide}{Guide to use for this scale. Defaults to \code{"none"}.} 49 | } 50 | \value{ 51 | A ggproto object inheriting from \code{Scale} 52 | } 53 | \description{ 54 | This set of scales defines new alpha scales for edge geoms equivalent to the 55 | ones already defined by ggplot2. See \code{\link[ggplot2:scale_alpha]{ggplot2::scale_alpha()}} for 56 | more information. The different geoms will know whether to use edge scales or 57 | the standard scales so it is not necessary to write \code{edge_alpha} in 58 | the call to the geom - just use \code{alpha}. 59 | } 60 | \seealso{ 61 | Other scale_edge_*: 62 | \code{\link{scale_edge_colour}}, 63 | \code{\link{scale_edge_fill}}, 64 | \code{\link{scale_edge_linetype}()}, 65 | \code{\link{scale_edge_shape}()}, 66 | \code{\link{scale_edge_size}()}, 67 | \code{\link{scale_edge_width}()}, 68 | \code{\link{scale_label_size}()} 69 | } 70 | \concept{scale_edge_*} 71 | -------------------------------------------------------------------------------- /man/scale_type.ggraph_geometry.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/geometry.R 3 | \name{scale_type.ggraph_geometry} 4 | \alias{scale_type.ggraph_geometry} 5 | \title{Define default scale type for geometry} 6 | \usage{ 7 | \method{scale_type}{ggraph_geometry}(x) 8 | } 9 | \description{ 10 | This function is quite useless as geometry is not meant to be scaled, but it 11 | is a requirement for ggplot2 to handle it correctly. 12 | } 13 | \keyword{internal} 14 | -------------------------------------------------------------------------------- /man/whigs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/data_whigs.R 3 | \docType{data} 4 | \name{whigs} 5 | \alias{whigs} 6 | \title{Membership network of American Whigs} 7 | \format{ 8 | The data is stored as an incidence matrix with persons as rows and 9 | organizations as columns. A 0 means no membership while a one means 10 | membership. 11 | } 12 | \source{ 13 | \url{https://github.com/kjhealy/revere/blob/master/data/PaulRevereAppD.csv} 14 | adapted from: 15 | 16 | Fischer, David H. (1995) \emph{Paul Revere's Ride}. Oxford University Press 17 | } 18 | \usage{ 19 | whigs 20 | } 21 | \description{ 22 | This dataset shows the membership of 136 colonial Americans in 5 whig 23 | organization and is a bipartite graph. The data appeared in the appendix to 24 | David Hackett Fischer's \emph{Paul Revere's Ride} (Oxford University Press, 25 | 1995) and compiled by Kieran Healy for the blog post 26 | \href{https://kieranhealy.org/blog/archives/2013/06/09/using-metadata-to-find-paul-revere/}{Using Metadata to Find Paul Revere}. 27 | } 28 | \keyword{datasets} 29 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /revdep/README.md: -------------------------------------------------------------------------------- 1 | # Revdeps 2 | 3 | ## New problems (1) 4 | 5 | |package |version |error |warning |note | 6 | |:-------|:-------|:------|:-------|:----| 7 | |[ggdag](problems.md#ggdag)|0.2.11 |__+1__ | |1 | 8 | 9 | -------------------------------------------------------------------------------- /revdep/cran.md: -------------------------------------------------------------------------------- 1 | ## revdepcheck results 2 | 3 | We checked 93 reverse dependencies, comparing R CMD check results across CRAN and dev versions of this package. 4 | 5 | * We saw 1 new problems 6 | * We failed to check 0 packages 7 | 8 | Issues with CRAN packages are summarised below. 9 | 10 | ### New problems 11 | (This reports the first line of each new failure) 12 | 13 | * ggdag 14 | checking tests ... ERROR 15 | 16 | -------------------------------------------------------------------------------- /revdep/failures.md: -------------------------------------------------------------------------------- 1 | *Wow, no problems at all. :)* -------------------------------------------------------------------------------- /revdep/problems.md: -------------------------------------------------------------------------------- 1 | # ggdag 2 | 3 |
4 | 5 | * Version: 0.2.11 6 | * GitHub: https://github.com/r-causal/ggdag 7 | * Source code: https://github.com/cran/ggdag 8 | * Date/Publication: 2024-01-24 15:30:05 UTC 9 | * Number of recursive dependencies: 103 10 | 11 | Run `revdepcheck::cloud_details(, "ggdag")` for more info 12 | 13 |
14 | 15 | ## Newly broken 16 | 17 | * checking tests ... ERROR 18 | ``` 19 | Running ‘spelling.R’ 20 | Running ‘testthat.R’ 21 | Running the tests in ‘tests/testthat.R’ failed. 22 | Complete output: 23 | > library(testthat) 24 | > library(ggdag) 25 | 26 | Attaching package: 'ggdag' 27 | 28 | The following object is masked from 'package:stats': 29 | ... 30 | • quick_plots/ggdag-collider-triangle-is-triangle-too.svg 31 | • quick_plots/ggdag-confounder-triangle-is-triangle.svg 32 | • relations/ggdag-ancestors-identifies-v-w1-and-z1.svg 33 | • relations/ggdag-descendants-identifies-y-x-and-z1.svg 34 | • relations/ggdag-parents-identifies-z2-x-w1-and-w2.svg 35 | • themes/theme-dag-gray-grid.svg 36 | • themes/theme-dag-gray.svg 37 | • themes/theme-dag-grid.svg 38 | Error: Test failures 39 | Execution halted 40 | ``` 41 | 42 | ## In both 43 | 44 | * checking installed package size ... NOTE 45 | ``` 46 | installed size is 8.2Mb 47 | sub-directories of 1Mb or more: 48 | doc 6.6Mb 49 | help 1.1Mb 50 | ``` 51 | 52 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/cactusTree.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | void cactusTreeCircle(Node* node, double x, double y, double scale, double alpha, double span, double overlap) { 10 | Rectangle r = {x, y, std::pow(node->weight(), scale), 0.0}; 11 | node->bounds = r; 12 | 13 | if (node->leaf()) return; 14 | 15 | std::vector children = node->getChildren(); 16 | 17 | std::sort(children.begin(), children.end(), [](Node* a, Node* b){return a->weight() < b->weight();}); 18 | std::vector ordered_children; 19 | double total_angle = 0.0; 20 | for (unsigned int i = 0; i < children.size(); i++) { 21 | total_angle += std::pow(children[i]->weight(), scale * (children.size() < 5 ? 2 : 0.75)); 22 | ordered_children.insert(ordered_children.begin() + int(ordered_children.size() / 2), children[i]); 23 | } 24 | 25 | alpha -= span / 2; 26 | 27 | for (unsigned int i = 0; i < ordered_children.size(); i++) { 28 | double local_span = 0.5 * span * std::pow(ordered_children[i]->weight(), scale * (children.size() < 5 ? 2 : 0.75)) / total_angle; 29 | alpha += local_span; 30 | double child_r = std::pow(ordered_children[i]->weight(), scale); 31 | double dist = node->bounds.width + child_r * overlap; 32 | double x2 = x + dist * std::cos(alpha); 33 | double y2 = y + dist * std::sin(alpha); 34 | cactusTreeCircle(ordered_children[i], x2, y2, scale, alpha, 3.926991, overlap); 35 | alpha += local_span; 36 | } 37 | } 38 | 39 | [[cpp11::register]] 40 | cpp11::writable::doubles_matrix<> cactusTree(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, double scale, double overlap, bool upright) { 41 | cpp11::writable::doubles_matrix<> circ(parent.size(), 3); 42 | unsigned int i; 43 | 44 | std::vector nodes = createHierarchy(parent, order, weight); 45 | 46 | Node* startNode = nodes[0]->getRoot(); 47 | startNode->tallyWeights(); 48 | if (startNode->nChildren() == 1) { 49 | startNode = startNode->getChildren()[0]; 50 | } 51 | double start_span = upright ? 3.926991 : 6.283185; 52 | cactusTreeCircle(startNode, 0.0, 0.0, scale, 1.570796, start_span, overlap); 53 | 54 | for (i = 0; i < nodes.size(); ++i) { 55 | circ(i, 0) = nodes[i]->bounds.x; 56 | circ(i, 1) = nodes[i]->bounds.y; 57 | circ(i, 2) = nodes[i]->bounds.width; 58 | delete nodes[i]; 59 | } 60 | 61 | return circ; 62 | } 63 | -------------------------------------------------------------------------------- /src/dendrogram.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | double max_leaf(cpp11::doubles& x, cpp11::logicals& leaf) { 7 | double max = NA_REAL; 8 | for (R_xlen_t i = 0; i < x.size(); ++i) { 9 | if (leaf[i] && !cpp11::is_na(x[i]) && (R_IsNA(max) || max < x[i])) { 10 | max = x[i]; 11 | } 12 | } 13 | return max; 14 | } 15 | 16 | void recurse_dendrogram(cpp11::list_of& graph, int node, cpp11::writable::doubles& x, cpp11::doubles& y, cpp11::logicals& leaf, double offset, bool repel, double pad, double ratio) { 17 | if (graph[node].size() == 0) { 18 | x[node] = offset; 19 | } else { 20 | double min_x = NA_REAL; 21 | double max_x = NA_REAL; 22 | for (int i = 0; i < graph[node].size(); ++i) { 23 | int child = graph[node][i] - 1; 24 | if (R_IsNA(x[child])) { 25 | recurse_dendrogram(graph, child, x, y, leaf, offset, repel, pad, ratio); 26 | offset = max_leaf(x, leaf); 27 | if (repel) { 28 | offset += (REAL(y)[node] + pad) * ratio; 29 | } else { 30 | offset += 1 + pad; 31 | } 32 | if (R_IsNA(min_x) || x[child] < min_x) min_x = x[child]; 33 | if (R_IsNA(max_x) || x[child] > max_x) max_x = x[child]; 34 | } 35 | } 36 | x[node] = (min_x + max_x) / 2; 37 | } 38 | } 39 | 40 | [[cpp11::register]] 41 | cpp11::writable::doubles dendrogram_spread(cpp11::list_of graph, cpp11::integers starts, cpp11::doubles y, cpp11::logicals leaf, bool repel, double pad, double ratio) { 42 | cpp11::writable::doubles x_loc(y.size()); 43 | std::fill(x_loc.begin(), x_loc.end(), NA_REAL); 44 | for (R_xlen_t i = 0; i < starts.size(); ++i) { 45 | recurse_dendrogram(graph, starts[i] - 1, x_loc, y, leaf, 0.0, repel, pad, ratio); 46 | } 47 | return x_loc; 48 | } 49 | -------------------------------------------------------------------------------- /src/hTree.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | void hLayout(Node* node, double x, double y, bool horizontal, double length) { 10 | Rectangle r = {x, y, 0.0, 0.0}; 11 | node->bounds = r; 12 | std::vector children = node->getChildren(); 13 | double next_length = length / 1.414214; 14 | for (unsigned int i = 0; i < children.size(); i++) { 15 | length *= -1; 16 | hLayout(children[i], horizontal ? x + length : x, horizontal ? y : y + length, !horizontal, next_length); 17 | } 18 | } 19 | 20 | [[cpp11::register]] 21 | cpp11::writable::doubles_matrix<> hTree(cpp11::integers parent, cpp11::integers order) { 22 | cpp11::writable::doubles_matrix<> pos(parent.size(), 2); 23 | unsigned int i; 24 | 25 | std::vector nodes = createHierarchy(parent, order); 26 | 27 | for (i = 0; i < nodes.size(); ++i) { 28 | nodes[i]->sortChildren(); 29 | } 30 | 31 | Node* startNode = nodes[0]->getRoot(); 32 | hLayout(startNode, 0, 0, false, 1.0); 33 | 34 | for (i = 0; i < nodes.size(); ++i) { 35 | pos(i, 0) = nodes[i]->bounds.x; 36 | pos(i, 1) = nodes[i]->bounds.y; 37 | delete nodes[i]; 38 | } 39 | 40 | return pos; 41 | } 42 | -------------------------------------------------------------------------------- /src/iciclePlot.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | void icicleLayout(Node* node, double x, double y) { 10 | Rectangle r = {x, y, node->weight(), node->height()}; 11 | node->bounds = r; 12 | std::vector children = node->getChildren(); 13 | if (children.size() != 0) { 14 | y += node->height(); 15 | for (unsigned int i = 0; i < children.size(); i++) { 16 | icicleLayout(children[i], x, y); 17 | x += children[i]->weight(); 18 | } 19 | } 20 | } 21 | 22 | [[cpp11::register]] 23 | cpp11::writable::doubles_matrix<> partitionTree(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, cpp11::doubles height) { 24 | cpp11::writable::doubles_matrix<> rect(parent.size(), 4); 25 | unsigned int i; 26 | 27 | std::vector nodes = createHierarchy(parent, order, weight, height); 28 | 29 | for (i = 0; i < nodes.size(); ++i) { 30 | nodes[i]->sortChildren(); 31 | } 32 | 33 | Node* startNode = nodes[0]->getRoot(); 34 | icicleLayout(startNode, 0, 0); 35 | 36 | for (i = 0; i < nodes.size(); ++i) { 37 | rect(i, 0) = nodes[i]->bounds.x; 38 | rect(i, 1) = nodes[i]->bounds.y; 39 | rect(i, 2) = nodes[i]->bounds.width; 40 | rect(i, 3) = nodes[i]->bounds.height; 41 | delete nodes[i]; 42 | } 43 | 44 | return rect; 45 | } 46 | -------------------------------------------------------------------------------- /src/nodes.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.h" 2 | 3 | #include 4 | 5 | std::vector createHierarchy(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight) { 6 | std::vector nodes; 7 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 8 | Node* node = new Node(i, order[i], weight[i]); 9 | nodes.push_back(node); 10 | } 11 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 12 | if (parent[i] >= 0) { 13 | nodes[parent[i]]->addNode(nodes[i]); 14 | } 15 | } 16 | return nodes; 17 | } 18 | 19 | std::vector createHierarchy(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, cpp11::doubles height) { 20 | std::vector nodes; 21 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 22 | Node* node = new Node(i, order[i], weight[i], height[i]); 23 | nodes.push_back(node); 24 | } 25 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 26 | if (parent[i] >= 0) { 27 | nodes[parent[i]]->addNode(nodes[i]); 28 | } 29 | } 30 | return nodes; 31 | } 32 | 33 | std::vector createHierarchy(cpp11::integers parent, cpp11::integers order) { 34 | std::vector nodes; 35 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 36 | Node* node = new Node(i, order[i], 0.0); 37 | nodes.push_back(node); 38 | } 39 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 40 | if (parent[i] >= 0) { 41 | nodes[parent[i]]->addNode(nodes[i]); 42 | } 43 | } 44 | return nodes; 45 | } 46 | 47 | std::vector createUnrooted(cpp11::integers parent, cpp11::integers order, cpp11::doubles length) { 48 | std::vector nodes; 49 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 50 | Node* node = new Node(i, order[i], 1, length[i]); 51 | nodes.push_back(node); 52 | } 53 | for (R_xlen_t i = 0; i < parent.size(); ++i) { 54 | if (parent[i] >= 0) { 55 | nodes[parent[i]]->addNode(nodes[i]); 56 | } 57 | } 58 | return nodes; 59 | } 60 | -------------------------------------------------------------------------------- /src/pathAttr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace cpp11::literals; 9 | 10 | [[cpp11::register]] 11 | cpp11::writable::data_frame pathAttr(cpp11::integers group, cpp11::doubles alpha, 12 | cpp11::doubles width, cpp11::strings lty, 13 | cpp11::strings colour, int ngroups) { 14 | cpp11::writable::logicals solid(ngroups); 15 | std::fill(solid.begin(), solid.end(), true); 16 | cpp11::writable::logicals constant(ngroups); 17 | std::fill(constant.begin(), constant.end(), true); 18 | 19 | int currentGroup, currentIndex, i; 20 | 21 | currentGroup = group[0]; 22 | currentIndex = 0; 23 | 24 | for (i = 1; i < group.size(); ++i) { 25 | if (group[i] == currentGroup) { 26 | if (solid[currentIndex] == TRUE) { 27 | solid[currentIndex] = lty[i] == "solid" && lty[i] == lty[i-1]; 28 | } 29 | if (constant[currentIndex] == TRUE) { 30 | constant[currentIndex] = 31 | ((alpha[i] == alpha[i-1]) || (cpp11::is_na(alpha[i]) && cpp11::is_na(alpha[i-1]))) && 32 | ((width[i] == width[i-1]) || (cpp11::is_na(width[i]) && cpp11::is_na(width[i-1]))) && 33 | ((lty[i] == lty[i-1]) || (cpp11::is_na(lty[i]) && cpp11::is_na(lty[i-1]))) && 34 | ((colour[i] == colour[i-1]) || (cpp11::is_na(colour[i]) && cpp11::is_na(colour[i-1]))); 35 | } 36 | } else { 37 | currentGroup = group[i]; 38 | ++currentIndex; 39 | } 40 | } 41 | 42 | return cpp11::writable::data_frame({ 43 | "solid"_nm = solid, 44 | "constant"_nm = constant 45 | }); 46 | } 47 | -------------------------------------------------------------------------------- /src/treemap.cpp: -------------------------------------------------------------------------------- 1 | #include "nodes.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | double w(std::vector& nodes) { 10 | double w = 0; 11 | for (unsigned int i = 0; i < nodes.size(); ++i) { 12 | w += nodes[i]->weight(); 13 | } 14 | return w; 15 | } 16 | void splitLayout(std::vector items, Rectangle r) { 17 | if (items.size() == 0) { 18 | return; 19 | } 20 | if (items.size() == 1) { 21 | items[0]->bounds = r; 22 | splitLayout(items[0]->getChildren(), r); // Layout the children within 23 | } else { 24 | Rectangle r1, r2; 25 | std::vector s1, s2; 26 | if (items.size() == 2) { 27 | s1.push_back(items[0]); 28 | s2.push_back(items[1]); 29 | } else { 30 | double halfSize = w(items) / 2; 31 | double wH = 0; 32 | double tmp = 0; 33 | bool completed = false; 34 | // Pick out half the weight into l1, half into l2 35 | for (unsigned int i = 0; i < items.size(); ++i) { 36 | if (completed) { 37 | s2.push_back(items[i]); 38 | } else { 39 | tmp = wH + items[i]->weight(); 40 | // Test if it got worse by picking another item 41 | if (std::abs(halfSize - tmp) > std::abs(halfSize - wH)) { 42 | s2.push_back(items[i]); 43 | completed = true; 44 | } else { 45 | s1.push_back(items[i]); 46 | wH = tmp; 47 | } 48 | } 49 | } 50 | } 51 | double w1 = w(s1); 52 | double w2 = w(s2); 53 | if (r.width > r.height) { 54 | r1.x = r.x; 55 | r1.y = r.y; 56 | r1.width = r.width * w1/(w1 + w2); 57 | r1.height = r.height; 58 | r2.x = r.x + r1.width; 59 | r2.y = r.y; 60 | r2.width = r.width - r1.width; 61 | r2.height = r.height; 62 | } else { 63 | r1.x = r.x; 64 | r1.y = r.y; 65 | r1.width = r.width; 66 | r1.height = r.height * w1/(w1 + w2); 67 | r2.x = r.x; 68 | r2.y = r.y + r1.height; 69 | r2.width = r.width; 70 | r2.height = r.height - r1.height; 71 | } 72 | splitLayout(s1, r1); 73 | splitLayout(s2, r2); 74 | } 75 | } 76 | 77 | [[cpp11::register]] 78 | cpp11::writable::doubles_matrix<> splitTreemap(cpp11::integers parent, cpp11::integers order, cpp11::doubles weight, double width, double height) { 79 | cpp11::writable::doubles_matrix<> rect(parent.size(), 4); 80 | unsigned int i; 81 | 82 | std::vector nodes = createHierarchy(parent, order, weight); 83 | 84 | for (i = 0; i < nodes.size(); ++i) { 85 | nodes[i]->sortChildren(); 86 | } 87 | 88 | Node* startNode = nodes[0]->getRoot(); 89 | Rectangle r = { 90 | 0, 91 | 0, 92 | width, 93 | height 94 | }; 95 | startNode->bounds = r; 96 | splitLayout(startNode->getChildren(), r); 97 | 98 | for (i = 0; i < nodes.size(); ++i) { 99 | rect(i, 0) = nodes[i]->bounds.x; 100 | rect(i, 1) = nodes[i]->bounds.y; 101 | rect(i, 2) = nodes[i]->bounds.width; 102 | rect(i, 3) = nodes[i]->bounds.height; 103 | delete nodes[i]; 104 | } 105 | 106 | return rect; 107 | } 108 | -------------------------------------------------------------------------------- /vignettes/edge_meme_wide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasp85/ggraph/9a0bfb1234044ca04b357a0ea77415d09e149bd5/vignettes/edge_meme_wide.jpg --------------------------------------------------------------------------------