├── .Rbuildignore ├── .github ├── .gitignore └── workflows │ ├── R-CMD-check.yaml │ ├── pkgdown.yaml │ ├── pr-commands.yaml │ └── test-coverage.yaml ├── .gitignore ├── CRAN-SUBMISSION ├── DESCRIPTION ├── LICENSE ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── guide_colormeter.R └── unexported-ggforce.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── ggcolormeter.Rproj └── man ├── figures ├── README-arc-radius-1.png ├── README-arc-theme-1.png ├── README-simple-usage-1.png ├── README-unnamed-chunk-10-1.png ├── README-unnamed-chunk-11-1.png ├── README-unnamed-chunk-12-1.png ├── README-unnamed-chunk-13-1.png ├── README-unnamed-chunk-14-1.png ├── README-unnamed-chunk-15-1.png ├── README-unnamed-chunk-16-1.png ├── README-unnamed-chunk-17-1.png ├── README-unnamed-chunk-18-1.png ├── README-unnamed-chunk-19-1.png ├── README-unnamed-chunk-2-1.png ├── README-unnamed-chunk-3-1.png ├── README-unnamed-chunk-4-1.png ├── README-unnamed-chunk-5-1.png ├── README-unnamed-chunk-6-1.png ├── README-unnamed-chunk-7-1.png ├── README-unnamed-chunk-8-1.png └── README-unnamed-chunk-9-1.png ├── guide_colormeter.Rd └── legend-coords.Rd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^_pkgdown\.yml$ 6 | ^docs$ 7 | ^pkgdown$ 8 | ^\.github$ 9 | ^codecov\.yml$ 10 | ^cran-comments\.md$ 11 | ^CRAN-SUBMISSION$ 12 | -------------------------------------------------------------------------------- /.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 | - {os: windows-latest, r: 'release'} 27 | - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} 28 | - {os: ubuntu-latest, r: 'release'} 29 | - {os: ubuntu-latest, r: 'oldrel-1'} 30 | - {os: ubuntu-latest, r: 'oldrel-2'} 31 | 32 | env: 33 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 34 | R_KEEP_PKG_SOURCE: yes 35 | 36 | steps: 37 | - uses: actions/checkout@v3 38 | 39 | - uses: r-lib/actions/setup-pandoc@v2 40 | 41 | - uses: r-lib/actions/setup-r@v2 42 | with: 43 | r-version: ${{ matrix.config.r }} 44 | http-user-agent: ${{ matrix.config.http-user-agent }} 45 | use-public-rspm: true 46 | 47 | - uses: r-lib/actions/setup-r-dependencies@v2 48 | with: 49 | extra-packages: any::rcmdcheck 50 | needs: check 51 | 52 | - uses: r-lib/actions/check-r-package@v2 53 | with: 54 | upload-snapshots: true 55 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | release: 9 | types: [published] 10 | workflow_dispatch: 11 | 12 | name: pkgdown 13 | 14 | jobs: 15 | pkgdown: 16 | runs-on: ubuntu-latest 17 | # Only restrict concurrency for non-PR jobs 18 | concurrency: 19 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 20 | env: 21 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 22 | permissions: 23 | contents: write 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - uses: r-lib/actions/setup-pandoc@v2 28 | 29 | - uses: r-lib/actions/setup-r@v2 30 | with: 31 | use-public-rspm: true 32 | 33 | - uses: r-lib/actions/setup-r-dependencies@v2 34 | with: 35 | extra-packages: any::pkgdown, local::. 36 | needs: website 37 | 38 | - name: Build site 39 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 40 | shell: Rscript {0} 41 | 42 | - name: Deploy to GitHub pages 🚀 43 | if: github.event_name != 'pull_request' 44 | uses: JamesIves/github-pages-deploy-action@v4.4.1 45 | with: 46 | clean: false 47 | branch: gh-pages 48 | folder: docs 49 | -------------------------------------------------------------------------------- /.github/workflows/pr-commands.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | issue_comment: 5 | types: [created] 6 | 7 | name: Commands 8 | 9 | jobs: 10 | document: 11 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/document') }} 12 | name: document 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | steps: 17 | - uses: actions/checkout@v3 18 | 19 | - uses: r-lib/actions/pr-fetch@v2 20 | with: 21 | repo-token: ${{ secrets.GITHUB_TOKEN }} 22 | 23 | - uses: r-lib/actions/setup-r@v2 24 | with: 25 | use-public-rspm: true 26 | 27 | - uses: r-lib/actions/setup-r-dependencies@v2 28 | with: 29 | extra-packages: any::roxygen2 30 | needs: pr-document 31 | 32 | - name: Document 33 | run: roxygen2::roxygenise() 34 | shell: Rscript {0} 35 | 36 | - name: commit 37 | run: | 38 | git config --local user.name "$GITHUB_ACTOR" 39 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 40 | git add man/\* NAMESPACE 41 | git commit -m 'Document' 42 | 43 | - uses: r-lib/actions/pr-push@v2 44 | with: 45 | repo-token: ${{ secrets.GITHUB_TOKEN }} 46 | 47 | style: 48 | if: ${{ github.event.issue.pull_request && (github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'OWNER') && startsWith(github.event.comment.body, '/style') }} 49 | name: style 50 | runs-on: ubuntu-latest 51 | env: 52 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 53 | steps: 54 | - uses: actions/checkout@v3 55 | 56 | - uses: r-lib/actions/pr-fetch@v2 57 | with: 58 | repo-token: ${{ secrets.GITHUB_TOKEN }} 59 | 60 | - uses: r-lib/actions/setup-r@v2 61 | 62 | - name: Install dependencies 63 | run: install.packages("styler") 64 | shell: Rscript {0} 65 | 66 | - name: Style 67 | run: styler::style_pkg() 68 | shell: Rscript {0} 69 | 70 | - name: commit 71 | run: | 72 | git config --local user.name "$GITHUB_ACTOR" 73 | git config --local user.email "$GITHUB_ACTOR@users.noreply.github.com" 74 | git add \*.R 75 | git commit -m 'Style' 76 | 77 | - uses: r-lib/actions/pr-push@v2 78 | with: 79 | repo-token: ${{ secrets.GITHUB_TOKEN }} 80 | -------------------------------------------------------------------------------- /.github/workflows/test-coverage.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: test-coverage 10 | 11 | jobs: 12 | test-coverage: 13 | runs-on: ubuntu-latest 14 | env: 15 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - uses: r-lib/actions/setup-r@v2 21 | with: 22 | use-public-rspm: true 23 | 24 | - uses: r-lib/actions/setup-r-dependencies@v2 25 | with: 26 | extra-packages: any::covr 27 | needs: coverage 28 | 29 | - name: Test coverage 30 | run: | 31 | covr::codecov( 32 | type = c("tests", "vignettes", "examples"), 33 | quiet = FALSE, 34 | clean = FALSE, 35 | install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package") 36 | ) 37 | shell: Rscript {0} 38 | 39 | - name: Show testthat output 40 | if: always() 41 | run: | 42 | ## -------------------------------------------------------------------- 43 | find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true 44 | shell: bash 45 | 46 | - name: Upload test results 47 | if: failure() 48 | uses: actions/upload-artifact@v3 49 | with: 50 | name: coverage-test-failures 51 | path: ${{ runner.temp }}/package 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | .Rdata 6 | .httr-oauth 7 | .DS_Store 8 | docs 9 | -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 0.2.0 2 | Date: 2024-01-22 14:22:38 UTC 3 | SHA: 2101920d6ccc9cf4269eda993a0b99b00733fd1b 4 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Type: Package 2 | Package: ggcolormeter 3 | Title: Colormeter Guide Extension 4 | Version: 0.2.0 5 | Authors@R: 6 | person("June", "Choe", , "jchoe001@gmail.com", role = c("aut", "cre", "cph"), 7 | comment = c(ORCID = "0000-0002-0701-921X")) 8 | Description: A 'ggplot2' guide extension for fill and color scales in the 9 | style of a dashboard meter. The dashboard legend maps onto continuous 10 | aesthetics and can be customized for its dimensions and the style of its 11 | various components including the labels and frames. Fine-grained control 12 | over the positioning of dashboard components is possible via an option to 13 | expose the legend-internal coordinate system. 14 | License: MIT + file LICENSE 15 | URL: https://github.com/yjunechoe/ggcolormeter, https://github.com/yjunechoe/ggcolormeter/issues, https://yjunechoe.github.io/ggcolormeter/ 16 | BugReports: https://github.com/yjunechoe/ggcolormeter/issues 17 | Depends: 18 | ggplot2, 19 | R (>= 4.1) 20 | Imports: 21 | grid (>= 4.1), 22 | gtable, 23 | polyclip 24 | Suggests: 25 | ggtext, 26 | scales 27 | Encoding: UTF-8 28 | LazyData: true 29 | Roxygen: list(markdown = TRUE) 30 | RoxygenNote: 7.2.3 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022 2 | COPYRIGHT HOLDER: ggcolormeter authors 3 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2022 ggcolormeter authors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | S3method(guide_gengrob,colormeter) 4 | S3method(makeContent,shape) 5 | export(guide_colormeter) 6 | importFrom(ggplot2,guide_gengrob) 7 | importFrom(grid,convertWidth) 8 | importFrom(grid,convertX) 9 | importFrom(grid,convertY) 10 | importFrom(grid,gpar) 11 | importFrom(grid,grob) 12 | importFrom(grid,is.unit) 13 | importFrom(grid,makeContent) 14 | importFrom(grid,nullGrob) 15 | importFrom(grid,polygonGrob) 16 | importFrom(grid,unit) 17 | importFrom(polyclip,polylineoffset) 18 | importFrom(polyclip,polyoffset) 19 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # ggcolormeter 0.2.0 2 | 3 | * Initial CRAN submission. 4 | -------------------------------------------------------------------------------- /R/guide_colormeter.R: -------------------------------------------------------------------------------- 1 | #' Colormeter legend coordinate system 2 | #' 3 | #' @description Due to the peculiar nature of the colormeter legend (e.g., dynamic size and positioning 4 | #' of color bars/arcs depending on the number of breaks), many parts of the legend are drawn in a 5 | #' mini isolated coordinate space. You can inspect this coordinate space with `debug = TRUE`. 6 | #' 7 | #' The coordinate space defaults to the x-y range of the legend "data", which considers the 8 | #' polar-transformed positioning of the color arcs/bars, the labels, and the dashboard circle. 9 | #' 10 | #' @keywords internal 11 | #' @name legend-coords 12 | #' 13 | #' @examples 14 | #' library(ggplot2) 15 | #' # A standard plot 16 | #' p <- ggplot(mtcars, aes(drat, hp)) + 17 | #' geom_point(aes(color = mpg)) 18 | #' # Colormeter guide for color scale 19 | #' p + 20 | #' scale_color_viridis_c( 21 | #' option = "inferno", 22 | #' breaks = scales::breaks_pretty(10), 23 | #' guide = guide_colormeter(debug = TRUE) 24 | #' ) 25 | NULL 26 | 27 | #' A color legend in the style of a dashboard meter 28 | #' 29 | #' @inheritParams ggplot2::guide_colorbar 30 | #' @inheritParams ggplot2::guide_colorsteps 31 | #' @param legend_size Size of the legend box. 32 | #' @param legend_padding Spacing between the color meter and the legend boundary. 33 | #' @param title_position <[`legend-coords`][legend-coords]> 2-length vector for the x/y-position of the legend title. 34 | #' @param arc_range <[`legend-coords`][legend-coords]> 2-length vector for the start and end angles of the color meter. 35 | #' @param arc_radius <[`legend-coords`][legend-coords]> Radius of the color meter. 36 | #' @param arc_width <[`legend-coords`][legend-coords]> Width of the arcs in the color meter. 37 | #' @param arc_gap <[`legend-coords`][legend-coords]> Gap between arcs in the color meter. 38 | #' @param arc_rounding <[`legend-coords`][legend-coords]> Rounding of arcs in the color meter. 39 | #' @param label_radius <[`legend-coords`][legend-coords]> Radius of the labels. 40 | #' @param dashboard_radius <[`legend-coords`][legend-coords]> Radius of the dashboard background. 41 | #' @param dashboard_color Dashboard background color. 42 | #' @param dashboard_fill Dashboard background fill. 43 | #' @param dashboard_linewidth Dashboard background line width. 44 | #' @param dashboard_linetype Dashboard background line type. 45 | #' @param clip_dashboard Whether the dashboard circle should clip to the legend boundary. 46 | #' @param close_dashboard Whether the dashboard should be closed where it meets the legend boundary. 47 | #' @param frame_color Color of the frame drawn around the arcs. 48 | #' @param frame_linewidth Width of the frame drawn around the arcs. 49 | #' @param frame_linetype Line type of the frame drawn around the arcs. 50 | #' @param aspect.ratio Aspect ratio for the legend. 51 | #' @param debug If `TRUE`, axes and origin for <[`legend-coords`][legend-coords]> are drawn over the legend for debugging. 52 | #' @param ... Ignored. 53 | #' 54 | #' @examples 55 | #' library(ggplot2) 56 | #' # A standard plot 57 | #' p <- ggplot(mtcars, aes(drat, hp)) + 58 | #' geom_point(aes(color = mpg)) 59 | #' # Colormeter guide for color scale 60 | #' p + 61 | #' scale_color_viridis_c( 62 | #' option = "inferno", 63 | #' breaks = scales::breaks_pretty(10), 64 | #' guide = guide_colormeter() 65 | #' ) 66 | #' 67 | #' @export 68 | #' @return A guide object of class 'colormeter' 69 | guide_colormeter <- function(title = ggplot2::waiver(), title.theme = NULL, label.theme = NULL, 70 | legend_size = unit(5, "lines"), legend_padding = unit(c(1.2, 1, 0.3, 1), "lines"), 71 | title_position = c(0, 0), arc_range = c(-4/7 * pi, 4/7 * pi), 72 | arc_radius = 1, arc_width = arc_radius/4, arc_gap = arc_radius/5, arc_rounding = 0, 73 | label_radius = arc_radius * 1.25, dashboard_radius = label_radius * 1.2, 74 | dashboard_color = "black", dashboard_fill = NA, 75 | dashboard_linewidth = 0.5, dashboard_linetype = 1, 76 | clip_dashboard = TRUE, close_dashboard = clip_dashboard, 77 | frame_color = NA, frame_linewidth = 0.5, frame_linetype = 1, 78 | aspect.ratio = 1, show.limits = NULL, debug = FALSE, 79 | reverse = FALSE, available_aes = c("colour", "color", "fill"), 80 | ...) { 81 | guide <- ggplot2::guide_colorsteps( 82 | even.steps = TRUE, ticks = FALSE, show.limits = show.limits, 83 | title = title, title.theme = title.theme, label.theme = label.theme, 84 | frame.colour = frame_color, frame.linewidth = frame_linewidth, frame.linetype = frame_linetype, 85 | reverse = reverse, available_aes = available_aes 86 | ) 87 | guide$legend_size <- legend_size 88 | guide$legend_padding <- legend_padding 89 | guide$title_position <- title_position 90 | guide$arc_range <- arc_range 91 | guide$arc_radius <- arc_radius 92 | guide$arc_width <- arc_width 93 | guide$arc_gap <- arc_gap 94 | guide$arc_rounding <- arc_rounding 95 | guide$label_radius <- label_radius 96 | guide$clip_dashboard <- clip_dashboard 97 | guide$close_dashboard <- close_dashboard 98 | guide$dashboard_radius <- dashboard_radius 99 | guide$dashboard_color <- dashboard_color 100 | guide$dashboard_fill <- dashboard_fill 101 | guide$dashboard_linewidth <- dashboard_linewidth 102 | guide$dashboard_linetype <- dashboard_linetype 103 | guide$aspect.ratio <- aspect.ratio 104 | guide$debug <- debug 105 | class(guide) <- c("colormeter", class(guide)) 106 | guide 107 | } 108 | 109 | #' @importFrom ggplot2 guide_gengrob 110 | #' @noRd 111 | #' @export 112 | #' @method guide_gengrob colormeter 113 | guide_gengrob.colormeter <- function(guide, theme) { 114 | 115 | n <- nrow(guide$bar) 116 | n_breaks <- n * 2 - 1 117 | 118 | arc_range <- guide$arc_range 119 | arc_gap <- guide$arc_gap 120 | 121 | bar_widths <- rep(pi/n_breaks, n_breaks) 122 | bar_widths[c(FALSE, TRUE)] <- bar_widths[1] * arc_gap 123 | bar_widths <- bar_widths * abs(diff(arc_range))/sum(bar_widths) 124 | bar_breaks <- (arc_range[1] + cumsum(c(0, bar_widths))) 125 | 126 | arcs <- data.frame( 127 | start = bar_breaks[-length(bar_breaks)], 128 | end = bar_breaks[-1], 129 | x0 = 0, 130 | y0 = 0, 131 | r0 = guide$arc_radius - guide$arc_width, 132 | r = guide$arc_radius, 133 | PANEL = 1, 134 | group = 1 135 | ) 136 | 137 | arc_data <- arcPaths(arcs, 360) 138 | arc_data$group <- match(arc_data$group, unique(arc_data$group)) 139 | arc_data <- arc_data[arc_data$group %% 2 == 1,] 140 | 141 | label <- guide$key$.label 142 | if (any(vapply(label, is.call, logical(1)))) { 143 | label <- lapply(label, function(l) { 144 | if (is.call(l)) 145 | substitute(expression(x), list(x = l)) 146 | else l 147 | }) 148 | label <- do.call(c, label) 149 | } 150 | if (!isTRUE(guide$show.limits)) { 151 | label <- c("", label, "") 152 | } 153 | label_radius <- guide$label_radius 154 | if (!length(label_radius) %in% c(1, length(label))) { 155 | stop("Length of `label_radius` must be 1 or equal to the number of labels") 156 | } 157 | label_data <- radial_transform001(label_radius, seq(arc_range[1], arc_range[2], length.out = length(label))) 158 | label.theme <- guide$label.theme %||% ggplot2::calc_element("legend.text", theme) 159 | label_grob <- grid::textGrob( 160 | label = label, 161 | rot = label.theme$angle, 162 | gp = grid::gpar( 163 | fontsize = label.theme$size, 164 | fontfamily = label.theme$family, 165 | fontface = label.theme$face, 166 | col = label.theme$colour, 167 | lineheight = label.theme$lineheight 168 | ), 169 | x = label_data$x, y = label_data$y, 170 | hjust = label.theme$hjust %||% guide$label.hjust %||% 0.5, 171 | vjust = label.theme$vjust %||% guide$label.vjust %||% 0.5, 172 | default.units = "native", 173 | name = "guide.label" 174 | ) 175 | 176 | # TODO: secondary labels at bar midpoints 177 | 178 | # label_grob <- ggplot2:::element_grob( 179 | # element = label.theme, label = c("", label, ""), 180 | # x = grid::unit(label_data$x, "native"), 181 | # y = grid::unit(label_data$y, "native"), 182 | # hjust = label.theme$title.hjust %||% 0.5, 183 | # vjust = label.theme$title.vjust %||% 0.5, 184 | # margin_x = FALSE, margin_y = TRUE 185 | # ) 186 | 187 | arc_grob <- shapeGrob( 188 | arc_data$x, arc_data$y, 189 | default.units = 'native', 190 | id = arc_data$group, 191 | expand = 0, 192 | radius = guide$arc_rounding, 193 | gp = grid::gpar( 194 | col = guide$frame.colour, 195 | fill = guide$bar$colour, 196 | lwd = guide$frame.linewidth * ggplot2::.pt, 197 | lty = guide$frame.linetype 198 | ) 199 | ) 200 | 201 | legend_expansion <- c(0, 0, 0, 0) 202 | # TODO: wrap up legend_expansion is experimental 203 | # legend_expansion <- rep_len(guide$legend_expansion, 4) 204 | xrange <- range(label_data$x) * (legend_expansion[c(4, 2)] + 1) # legend_expansion[c(4, 2)] 205 | yrange <- range(label_data$y) * (legend_expansion[c(3, 1)] + 1) # legend_expansion[c(3, 1)] 206 | size <- guide$legend_size 207 | width <- size * abs(diff(xrange))/2 * sum(legend_expansion[c(2, 4)], 1) 208 | height <- size * abs(diff(yrange))/2 * guide$aspect.ratio * sum(legend_expansion[c(1, 3)], 1) 209 | width <- grid::convertUnit(width, "cm") 210 | height <- grid::convertUnit(height, "cm") 211 | 212 | legend_vp <- grid::viewport(xscale = xrange, yscale = yrange, width = width, height = height, 213 | gp = grid::gpar(lineheight = label.theme$lineheight)) 214 | 215 | colormeter_grob <- grid::grobTree(arc_grob, label_grob, vp = legend_vp) 216 | 217 | background_grob <- ggplot2::element_render(theme, "legend.background") 218 | 219 | title.theme <- guide$title.theme %||% ggplot2::calc_element("legend.title", theme) 220 | title.theme$hjust <- title.theme$hjust + 0.5 221 | title.hjust <- guide$title.hjust %||% title.theme$hjust 222 | title.vjust <- guide$title.vjust %||% title.theme$vjust %||% 0.5 223 | title_grob <- ggplot2::element_grob(title.theme, label = guide$title, 224 | hjust = title.hjust, vjust = title.vjust, 225 | margin_x = TRUE, margin_y = TRUE) 226 | title_grob$name <- "guide.title" 227 | title_grob$vp <- legend_vp 228 | title_grob$children[[1]]$x <- grid::unit(guide$title_position[1], "native") 229 | title_grob$children[[1]]$y <- grid::unit(guide$title_position[2], "native") 230 | 231 | 232 | legend_padding <- rep_len(guide$legend_padding, 4) 233 | if (!grid::is.unit(legend_padding)) {legend_padding <- grid::unit(legend_padding, "lines")} 234 | 235 | dashboard_data <- radial_transform001(guide$dashboard_radius, seq(0, 2 * pi, length.out = 360)) 236 | dashboard_gp <- grid::gpar(col = guide$dashboard_color, fill = guide$dashboard_fill, 237 | lwd = guide$dashboard_linewidth, lty = guide$dashboard_linetype) 238 | dashboard_grob <- grid::polygonGrob( 239 | x = grid::unit(dashboard_data$x, "native"), 240 | y = grid::unit(dashboard_data$y, "native") * (1 + (guide$aspect.ratio - 1)/2), 241 | gp = dashboard_gp, vp = legend_vp 242 | ) 243 | 244 | gt <- gtable::gtable(widths = width, heights = height) 245 | gt <- gtable::gtable_add_padding(gt, padding = legend_padding) 246 | 247 | gt <- gtable::gtable_add_grob(gt, background_grob, name = "background", 248 | clip = "off", t = 1, r = 3, b = 3, l = 1) 249 | gt <- gtable::gtable_add_grob(gt, dashboard_grob, name = "dashboard", 250 | clip = guide$clip_dashboard, t = 1, r = 3, b = 3, l = 1) 251 | gt <- gtable::gtable_add_grob(gt, colormeter_grob, name = "colormeter", 252 | clip = "off", t = 2, r = 2, b = 2, l = 2) 253 | gt <- gtable::gtable_add_grob(gt, title_grob, 254 | name = "title", clip = "off", t = 2, r = 2, b = 2, l = 2) 255 | gt <- gtable::gtable_add_grob(gt, grid::editGrob(background_grob, gp = grid::gpar(fill = NA)), name = "outline", 256 | clip = "off", t = 1, r = 3, b = 3, l = 1) 257 | 258 | if (guide$close_dashboard) { 259 | dashboard_border_gp <- dashboard_gp 260 | dashboard_border_gp$fill <- NA 261 | dashboard_border <- grid::rectGrob( 262 | width = grid::convertUnit(sum(gt$widths), "cm"), 263 | height = grid::convertUnit(sum(gt$heights), "cm"), 264 | gp = dashboard_border_gp, 265 | vp = grid::editViewport(legend_vp, mask = grid::editGrob(dashboard_grob, gp = grid::gpar(fill = "white"))) 266 | ) 267 | gt <- gtable::gtable_add_grob(gt, dashboard_border, name = "dashboard_close", 268 | clip = "off", t = 1, r = 3, b = 3, l = 1) 269 | } 270 | 271 | if (guide$debug) { 272 | gt <- gtable::gtable_filter(gt, "background", invert = TRUE) 273 | gt$grobs[[which(gt$layout$name == "outline")]]$gp <- grid::gpar(lty = 5, fill = NA, col = "turquoise") 274 | xaxis <- grid::xaxisGrob(vp = legend_vp) 275 | yaxis <- grid::yaxisGrob(vp = legend_vp) 276 | origin <- grid::pointsGrob(0, 0, default.units = "native", vp = legend_vp) 277 | gt <- gtable::gtable_add_grob(gt, grid::grobTree(xaxis, yaxis, origin, gp = grid::gpar(col = "steelblue")), 278 | name = "axes", clip = "off", t = 2, r = 2, b = 2, l = 2) 279 | } 280 | 281 | gt 282 | 283 | } 284 | -------------------------------------------------------------------------------- /R/unexported-ggforce.R: -------------------------------------------------------------------------------- 1 | # nocov start 2 | `%||%` <- function(lhs, rhs) { 3 | if (!is.null(lhs)) lhs else rhs 4 | } 5 | 6 | #' @importFrom grid is.unit grob gpar polygonGrob unit 7 | shapeGrob <- function(x = c(0, 0.5, 1, 0.5), y = c(0.5, 1, 0.5, 0), id = NULL, 8 | id.lengths = NULL, expand = 0, radius = 0, 9 | default.units = 'npc', name = NULL, gp = gpar(), 10 | vp = NULL) { 11 | if (as.numeric(expand) == 0 && as.numeric(radius) == 0) { 12 | grob <- polygonGrob( 13 | x = x, y = y, id = id, id.lengths = id.lengths, 14 | default.units = default.units, name = name, gp = gp, vp = vp 15 | ) 16 | return(grob) 17 | } 18 | if (!is.unit(x)) { 19 | x <- unit(x, default.units) 20 | } 21 | if (!is.unit(y)) { 22 | y <- unit(y, default.units) 23 | } 24 | if (!is.unit(expand)) { 25 | expand <- unit(expand, default.units) 26 | } 27 | if (!is.unit(radius)) { 28 | radius <- unit(radius, default.units) 29 | } 30 | if (as.numeric(radius) < 0) { 31 | stop('radius must be positive', call. = FALSE) 32 | } 33 | if (is.null(id)) { 34 | if (is.null(id.lengths)) { 35 | id <- rep(1, length(x)) 36 | } else { 37 | id <- rep(seq_along(id.lengths), id.lengths) 38 | if (length(id) != length(x)) { 39 | stop('id.lengths must sum up to the number of points', call. = FALSE) 40 | } 41 | } 42 | } 43 | x <- x[order(id)] 44 | y <- y[order(id)] 45 | grob( 46 | x = x, y = y, id = id, expand = expand, radius = radius, name = name, 47 | gp = gp, vp = vp, cl = 'shape' 48 | ) 49 | } 50 | 51 | #' @importFrom grid makeContent convertX convertY convertWidth gpar polygonGrob nullGrob unit 52 | #' @importFrom polyclip polyoffset polylineoffset 53 | #' @keywords internal 54 | #' @export 55 | #' @method makeContent shape 56 | makeContent.shape <- function(x) { 57 | id.length <- lengths(split(seq_along(x$id), x$id)) 58 | type <- ifelse(id.length == 1, 'point', 59 | ifelse(id.length == 2, 'line', 'polygon')) 60 | x_new <- convertX(x$x, 'mm', TRUE) 61 | x_new <- split(x_new, x$id) 62 | y_new <- convertY(x$y, 'mm', TRUE) 63 | y_new <- split(y_new, x$id) 64 | polygons <- Map(list, x = x_new, y = y_new) 65 | poly <- split(polygons, type) 66 | expand <- convertWidth(x$expand, 'mm', TRUE) 67 | radius <- convertWidth(x$radius, 'mm', TRUE) 68 | expand <- expand - radius 69 | if (expand != 0) { 70 | if (!is.null(poly$polygon)) { 71 | poly$polygon <- lapply(poly$polygon, polyoffset, delta = expand, 72 | jointype = 'miter', miterlim = 1000) 73 | } 74 | if (expand > 0) { 75 | if (!is.null(poly$line)) { 76 | poly$line <- lapply(poly$line, polylineoffset, delta = expand, 77 | jointype = 'square', endtype = 'opensquare') 78 | } 79 | poly$point <- pointoffset(poly$point, expand, type = 'square') 80 | } 81 | } 82 | if (radius != 0) { 83 | if (!is.null(poly$polygon)) { 84 | not_empty <- lengths(poly$polygon) != 0 85 | poly$polygon[not_empty] <- lapply(poly$polygon[not_empty], polyoffset, 86 | delta = radius, jointype = 'round') 87 | } 88 | if (expand > 0) { 89 | if (!is.null(poly$line)) { 90 | not_empty <- lengths(poly$line) != 0 91 | poly$line[not_empty] <- lapply(poly$line[not_empty], polyoffset, 92 | delta = radius, jointype = 'round') 93 | } 94 | if (!is.null(poly$point)) { 95 | not_empty <- lengths(poly$point) != 0 96 | poly$point[not_empty] <- lapply(poly$point[not_empty], polyoffset, 97 | delta = radius, jointype = 'round') 98 | } 99 | } else { 100 | if (!is.null(poly$line)) { 101 | poly$line <- lapply(poly$line, polylineoffset, delta = radius, 102 | jointype = 'round', endtype = 'openround') 103 | } 104 | poly$point <- pointoffset(poly$point, radius, type = 'circle') 105 | } 106 | } 107 | polygons[type == 'polygon'] <- lapply(poly$polygon, function(d) if (length(d) == 0) list() else d[[1]]) 108 | polygons[type == 'line'] <- lapply(poly$line, function(d) if (length(d) == 0) list() else d[[1]]) 109 | polygons[type == 'point'] <- lapply(poly$point, function(d) if (length(d) == 0) list() else d[[1]]) 110 | x$id <- rep(seq_along(polygons), sapply(polygons, function(p) length(p$x))) 111 | x_new <- unlist(lapply(polygons, `[[`, 'x')) 112 | y_new <- unlist(lapply(polygons, `[[`, 'y')) 113 | if (length(x_new) == 0) return(nullGrob()) 114 | x$x <- unit(x_new, 'mm') 115 | x$y <- unit(y_new, 'mm') 116 | x$cl <- 'polygon' 117 | class(x)[1] <- 'polygon' 118 | x 119 | } 120 | 121 | pointoffset <- function(A, delta, type) { 122 | if (length(A) == 0) return(A) 123 | switch( 124 | type, 125 | square = { 126 | square <- list(x = c(-delta, -delta, delta, delta), 127 | y = c(-delta, delta, delta, -delta)) 128 | x <- split(rep(sapply(A, `[[`, 'x'), each = 4) + square$x, 129 | rep(seq_along(A), each = 4)) 130 | y <- split(rep(sapply(A, `[[`, 'y'), each = 4) + square$y, 131 | rep(seq_along(A), each = 4)) 132 | lapply(Map(list, x = x, y = y), list) 133 | }, 134 | circle = { 135 | detail <- 100 136 | radi <- seq(0, 2 * pi, length.out = detail + 1)[-(detail + 1)] 137 | circle <- list(x = cos(radi) * delta, y = sin(radi) * delta) 138 | x <- split(rep(sapply(A, `[[`, 'x'), each = detail) + circle$x, 139 | rep(seq_along(A), each = detail)) 140 | y <- split(rep(sapply(A, `[[`, 'y'), each = detail) + circle$y, 141 | rep(seq_along(A), each = detail)) 142 | lapply(Map(list, x = x, y = y), list) 143 | } 144 | ) 145 | } 146 | 147 | radial_transform001 <- function(r, a) {data.frame(x = r * sin(a), y = r * cos(a))} 148 | 149 | # Modified 150 | arcPaths <- function(data, n) { 151 | data <- data[data$start != data$end, ] 152 | data$nControl <- ceiling(n / (2 * pi) * abs(data$end - data$start)) 153 | data$nControl[data$nControl < 3] <- 3 154 | extraData <- !names(data) %in% c('r0', 'r', 'start', 'end', 'group') 155 | data$group <- make.unique(as.character(data$group)) 156 | paths <- lapply(seq_len(nrow(data)), function(i) { 157 | path <- data.frame( 158 | a = seq(data$start[i], data$end[i], length.out = data$nControl[i]), 159 | r = data$r[i] 160 | ) 161 | if ('r0' %in% names(data)) { 162 | if (data$r0[i] != 0) { 163 | path <- rbind( 164 | path, 165 | data.frame(a = rev(path$a), r = data$r0[i]) 166 | ) 167 | } else { 168 | path <- rbind( 169 | path, 170 | data.frame(a = data$start[i], r = 0) 171 | ) 172 | } 173 | } 174 | path$group <- data$group[i] 175 | path$index <- seq(0, 1, length.out = nrow(path)) 176 | path <- cbind(path, data[rep(i, nrow(path)), extraData, drop = FALSE]) 177 | }) 178 | paths <- do.call(rbind, paths) 179 | paths <- cbind( 180 | paths[, !names(paths) %in% c('r', 'a')], 181 | radial_transform001(paths$r, paths$a) 182 | ) 183 | paths$x <- paths$x + paths$x0 184 | paths$y <- paths$y + paths$y0 185 | if ('explode' %in% names(data)) { 186 | exploded <- data$explode != 0 187 | if (any(exploded)) { 188 | exploder <- radial_transform001( 189 | data$explode[exploded], 190 | data$start[exploded] + (data$end[exploded] - data$start[exploded]) / 2 191 | ) 192 | explodedPaths <- paths$group %in% which(exploded) 193 | exploderInd <- as.integer(factor(paths$group[explodedPaths])) 194 | paths$x[explodedPaths] <- 195 | paths$x[explodedPaths] + exploder$x[exploderInd] 196 | paths$y[explodedPaths] <- 197 | paths$y[explodedPaths] + exploder$y[exploderInd] 198 | } 199 | } 200 | paths[, !names(paths) %in% c('x0', 'y0', 'exploded')] 201 | } 202 | # nocov end 203 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%", 13 | dev.args = list(png = list(type = "cairo")), 14 | fig.retina = 2 15 | ) 16 | ``` 17 | 18 | # ggcolormeter 19 | 20 | 21 | [![](https://img.shields.io/badge/devel%20version-`r as.character(packageVersion('ggcolormeter'))`-gogreen.svg)](https://github.com/yjunechoe/ggcolormeter) 22 | [![R-CMD-check](https://github.com/yjunechoe/ggcolormeter/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/yjunechoe/ggcolormeter/actions/workflows/R-CMD-check.yaml) 23 | [![Codecov test coverage](https://codecov.io/gh/yjunechoe/ggcolormeter/branch/main/graph/badge.svg)](https://app.codecov.io/gh/yjunechoe/ggcolormeter?branch=main) 24 | 25 | 26 | The `{ggcolormeter}` package provides a single function [`guide_colormeter()`](https://yjunechoe.github.io/ggcolormeter/reference/guide_colormeter.html), which is a `{ggplot2}` color/fill legend **guide extension** in the style of a dashboard meter. 27 | 28 | ## Installation 29 | 30 | ```{r, eval=FALSE} 31 | install.packages("ggcolormeter") 32 | # or 33 | remotes::install_github("yjunechoe/ggcolormeter") 34 | ``` 35 | 36 | 37 | ## Simple usage 38 | 39 | ```{r simple-usage} 40 | library(ggplot2) 41 | library(ggcolormeter) 42 | 43 | theme_set(theme_classic()) 44 | 45 | p <- ggplot(mtcars, aes(drat, hp)) + 46 | geom_point(aes(color = mpg)) 47 | 48 | p + 49 | scale_color_viridis_c( 50 | option = "inferno", 51 | breaks = scales::breaks_pretty(10), 52 | guide = guide_colormeter() 53 | ) 54 | ``` 55 | 56 | # Colormeter guide theme components 57 | 58 | The colormeter guide has argument families for styling 5 distinct components of the guide: 59 | 60 | 1) [Size and aspect](https://github.com/yjunechoe/ggcolormeter#1-size-and-aspect) 61 | 2) [Arc](https://github.com/yjunechoe/ggcolormeter#2-arc) 62 | 3) [Label](https://github.com/yjunechoe/ggcolormeter#3-label) 63 | 4) [Dashboard](https://github.com/yjunechoe/ggcolormeter#4-dashboard) 64 | 5) [Frame](https://github.com/yjunechoe/ggcolormeter#5-frame) 65 | 66 | Position of these theme elements is relative to the [guide-internal coordinate system](https://yjunechoe.github.io/ggcolormeter/reference/legend-coords.html), which you can inspect with the `debug = TRUE` argument. 67 | 68 | ## 1) Size and aspect 69 | 70 | The colormeter legend is a bit pecular in that its size doesn't expand with more keys: the colormeter has a fixed size and shape, and its elements are packed inside it. 71 | 72 | You can primarily control the size of the legend with `legend_size` and `aspect.ratio` 73 | 74 | ```{r} 75 | p + 76 | scale_color_viridis_c( 77 | option = "inferno", 78 | breaks = scales::breaks_pretty(10), 79 | guide = guide_colormeter( 80 | legend_size = unit(3, "cm"), 81 | aspect.ratio = .8 82 | ) 83 | ) 84 | ``` 85 | 86 | Note that the usual legend background is still present and different from the dashboard circle: 87 | 88 | ```{r} 89 | p + 90 | scale_color_viridis_c( 91 | option = "inferno", 92 | breaks = scales::breaks_pretty(10), 93 | guide = guide_colormeter( 94 | legend_size = unit(3, "cm"), 95 | aspect.ratio = .8 96 | ) 97 | ) + 98 | theme(legend.background = element_rect(color = "red", fill = "pink")) 99 | ``` 100 | 101 | Most of the time you'd want to remove this legend background, as the dashboard serves that purpose: 102 | 103 | ```{r} 104 | p + 105 | scale_color_viridis_c( 106 | option = "inferno", 107 | breaks = scales::breaks_pretty(10), 108 | guide = guide_colormeter( 109 | ) 110 | ) + 111 | theme( 112 | legend.position = c(.85, .75), 113 | legend.background = element_blank() 114 | ) 115 | ``` 116 | 117 | ## 2) Arc 118 | 119 | ```{r} 120 | formals(guide_colormeter)[grepl("arc", names(formals(guide_colormeter)))] 121 | ``` 122 | 123 | Non-positional aesthetic arguments for the color arc: 124 | 125 | ```{r arc-theme} 126 | p + 127 | scale_color_viridis_c( 128 | option = "inferno", 129 | breaks = scales::breaks_pretty(10), 130 | guide = guide_colormeter( 131 | arc_width = 1/6, # thinner arcs 132 | arc_gap = 1/3, # bigger gaps 133 | arc_rounding = 0.03 # rounded corners 134 | ) 135 | ) 136 | ``` 137 | 138 | By default, label and dashboard radii are derived from `arc_radius`: 139 | 140 | ```{r arc-radius} 141 | p + 142 | scale_color_viridis_c( 143 | option = "inferno", 144 | breaks = scales::breaks_pretty(10), 145 | guide = guide_colormeter( 146 | arc_radius = 1.2 147 | ) 148 | ) 149 | ``` 150 | 151 | You can use `arc_range` to set the start and end angles of the color meter, which may yield different shapes: 152 | 153 | ```{r} 154 | p + 155 | scale_color_viridis_c( 156 | option = "inferno", 157 | breaks = scales::breaks_pretty(5), # half the arcs 158 | guide = guide_colormeter( 159 | arc_range = c(-pi/2, 0) # quarter circle 160 | ) 161 | ) 162 | ``` 163 | 164 | The defaults aren't great for when you change from the dashboard shape. Some manual adjustments may be desirable: 165 | 166 | ```{r} 167 | p + 168 | scale_color_viridis_c( 169 | option = "inferno", 170 | breaks = scales::breaks_pretty(5), 171 | guide = guide_colormeter( 172 | arc_range = c(-pi/2, 0), 173 | title_position = c(-.2, .2), # moves title left and up from center 174 | legend_padding = grid::unit(0.7, "lines") # pads relative to legend label 175 | ) 176 | ) 177 | ``` 178 | 179 | ## 3) Label 180 | 181 | ```{r} 182 | formals(guide_colormeter)[grepl("label", names(formals(guide_colormeter)))] 183 | ``` 184 | 185 | By default, the dashboard radius is derived from `label_radius`: 186 | 187 | ```{r} 188 | p + 189 | scale_color_viridis_c( 190 | option = "inferno", 191 | breaks = scales::breaks_pretty(10), 192 | guide = guide_colormeter( 193 | label_radius = 1.5 194 | ) 195 | ) 196 | ``` 197 | 198 | Like `ggplot2::guide_colorsteps()`, the argument `show.limits` controls labeling the limits of the scale: 199 | 200 | ```{r} 201 | p + 202 | scale_color_viridis_c( 203 | option = "inferno", 204 | breaks = scales::breaks_pretty(10), 205 | guide = guide_colormeter( 206 | label_radius = 1.3, 207 | show.limits = TRUE 208 | ) 209 | ) 210 | ``` 211 | 212 | ## 4) Dashboard 213 | 214 | ```{r} 215 | formals(guide_colormeter)[grepl("dashboard", names(formals(guide_colormeter)))] 216 | ``` 217 | 218 | `dashboard_radius` controls the radius of just the dashboard circle 219 | 220 | ```{r} 221 | p + 222 | scale_color_viridis_c( 223 | option = "inferno", 224 | breaks = scales::breaks_pretty(10), 225 | guide = guide_colormeter( 226 | dashboard_radius = 1.2, 227 | ) 228 | ) 229 | ``` 230 | 231 | By default, the dashboard is clipped to the legend boundary, which can be turned off: 232 | 233 | ```{r} 234 | p + 235 | scale_color_viridis_c( 236 | option = "inferno", 237 | breaks = scales::breaks_pretty(10), 238 | guide = guide_colormeter( 239 | title = "mpg

240 | miles per gallon", 241 | clip_dashboard = FALSE 242 | ) 243 | ) + 244 | theme(legend.title = ggtext::element_markdown(vjust = -.6)) 245 | ``` 246 | 247 | Non-positional aesthetic arguments for the dashboard: 248 | 249 | ```{r} 250 | p + 251 | scale_color_viridis_c( 252 | option = "inferno", 253 | breaks = scales::breaks_pretty(10), 254 | guide = guide_colormeter( 255 | dashboard_fill = "skyblue", 256 | dashboard_color = "steelblue", 257 | dashboard_linetype = 5, 258 | dashboard_linewidth = 4 259 | ) 260 | ) 261 | ``` 262 | 263 | ## 5) Frame 264 | 265 | ```{r} 266 | formals(guide_colormeter)[grepl("frame", names(formals(guide_colormeter)))] 267 | ``` 268 | 269 | Frames simply decorate the color arcs/bars: 270 | 271 | ```{r} 272 | p + 273 | scale_color_viridis_c( 274 | option = "inferno", 275 | breaks = scales::breaks_pretty(10), 276 | guide = guide_colormeter( 277 | frame_color = "black", 278 | frame_linewidth = .3 279 | ) 280 | ) 281 | ``` 282 | 283 | ## Miscellaneous 284 | 285 | Set `debug = TRUE` to inspect the internal legend coordinate system (for deciding on `dashboard_radius`, `arc_width`, `title_position`, etc.): 286 | 287 | ```{r} 288 | p + 289 | scale_color_viridis_c( 290 | option = "inferno", 291 | breaks = scales::breaks_pretty(10), 292 | guide = guide_colormeter(debug = TRUE) 293 | ) 294 | ``` 295 | 296 | Puttings labels inside the arc: 297 | 298 | ```{r} 299 | p + 300 | scale_color_viridis_c( 301 | option = "inferno", 302 | breaks = scales::breaks_pretty(5), 303 | guide = guide_colormeter( 304 | arc_width = 0.1, 305 | label_radius = .7, 306 | aspect.ratio = 1.1, 307 | dashboard_color = NA 308 | ) 309 | ) + 310 | theme(legend.position = c(.85, .75)) 311 | ``` 312 | 313 | ## Acknowledgments 314 | 315 | - Thomas Lin Pedersen for [`{ggforce}`](https://github.com/thomasp85/ggforce), whose several unexported functions are used in this package. 316 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # ggcolormeter 5 | 6 | 7 | 8 | [![](https://img.shields.io/badge/devel%20version-0.2.0-gogreen.svg)](https://github.com/yjunechoe/ggcolormeter) 9 | [![R-CMD-check](https://github.com/yjunechoe/ggcolormeter/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/yjunechoe/ggcolormeter/actions/workflows/R-CMD-check.yaml) 10 | [![Codecov test 11 | coverage](https://codecov.io/gh/yjunechoe/ggcolormeter/branch/main/graph/badge.svg)](https://app.codecov.io/gh/yjunechoe/ggcolormeter?branch=main) 12 | 13 | 14 | The `{ggcolormeter}` package provides a single function 15 | [`guide_colormeter()`](https://yjunechoe.github.io/ggcolormeter/reference/guide_colormeter.html), 16 | which is a `{ggplot2}` color/fill legend **guide extension** in the 17 | style of a dashboard meter. 18 | 19 | ## Installation 20 | 21 | ``` r 22 | install.packages("ggcolormeter") 23 | # or 24 | remotes::install_github("yjunechoe/ggcolormeter") 25 | ``` 26 | 27 | ## Simple usage 28 | 29 | ``` r 30 | library(ggplot2) 31 | library(ggcolormeter) 32 | 33 | theme_set(theme_classic()) 34 | 35 | p <- ggplot(mtcars, aes(drat, hp)) + 36 | geom_point(aes(color = mpg)) 37 | 38 | p + 39 | scale_color_viridis_c( 40 | option = "inferno", 41 | breaks = scales::breaks_pretty(10), 42 | guide = guide_colormeter() 43 | ) 44 | ``` 45 | 46 | 47 | 48 | # Colormeter guide theme components 49 | 50 | The colormeter guide has argument families for styling 5 distinct 51 | components of the guide: 52 | 53 | 1) [Size and 54 | aspect](#1-size-and-aspect) 55 | 2) [Arc](#2-arc) 56 | 3) [Label](#3-label) 57 | 4) [Dashboard](#4-dashboard) 58 | 5) [Frame](#5-frame) 59 | 60 | Position of these theme elements is relative to the [guide-internal 61 | coordinate 62 | system](https://yjunechoe.github.io/ggcolormeter/reference/legend-coords.html), 63 | which you can inspect with the `debug = TRUE` argument. 64 | 65 | ## 1) Size and aspect 66 | 67 | The colormeter legend is a bit pecular in that its size doesn’t expand 68 | with more keys: the colormeter has a fixed size and shape, and its 69 | elements are packed inside it. 70 | 71 | You can primarily control the size of the legend with `legend_size` and 72 | `aspect.ratio` 73 | 74 | ``` r 75 | p + 76 | scale_color_viridis_c( 77 | option = "inferno", 78 | breaks = scales::breaks_pretty(10), 79 | guide = guide_colormeter( 80 | legend_size = unit(3, "cm"), 81 | aspect.ratio = .8 82 | ) 83 | ) 84 | ``` 85 | 86 | 87 | 88 | Note that the usual legend background is still present and different 89 | from the dashboard circle: 90 | 91 | ``` r 92 | p + 93 | scale_color_viridis_c( 94 | option = "inferno", 95 | breaks = scales::breaks_pretty(10), 96 | guide = guide_colormeter( 97 | legend_size = unit(3, "cm"), 98 | aspect.ratio = .8 99 | ) 100 | ) + 101 | theme(legend.background = element_rect(color = "red", fill = "pink")) 102 | ``` 103 | 104 | 105 | 106 | Most of the time you’d want to remove this legend background, as the 107 | dashboard serves that purpose: 108 | 109 | ``` r 110 | p + 111 | scale_color_viridis_c( 112 | option = "inferno", 113 | breaks = scales::breaks_pretty(10), 114 | guide = guide_colormeter( 115 | ) 116 | ) + 117 | theme( 118 | legend.position = c(.85, .75), 119 | legend.background = element_blank() 120 | ) 121 | ``` 122 | 123 | 124 | 125 | ## 2) Arc 126 | 127 | ``` r 128 | formals(guide_colormeter)[grepl("arc", names(formals(guide_colormeter)))] 129 | #> $arc_range 130 | #> c(-4/7 * pi, 4/7 * pi) 131 | #> 132 | #> $arc_radius 133 | #> [1] 1 134 | #> 135 | #> $arc_width 136 | #> arc_radius/4 137 | #> 138 | #> $arc_gap 139 | #> arc_radius/5 140 | #> 141 | #> $arc_rounding 142 | #> [1] 0 143 | ``` 144 | 145 | Non-positional aesthetic arguments for the color arc: 146 | 147 | ``` r 148 | p + 149 | scale_color_viridis_c( 150 | option = "inferno", 151 | breaks = scales::breaks_pretty(10), 152 | guide = guide_colormeter( 153 | arc_width = 1/6, # thinner arcs 154 | arc_gap = 1/3, # bigger gaps 155 | arc_rounding = 0.03 # rounded corners 156 | ) 157 | ) 158 | ``` 159 | 160 | 161 | 162 | By default, label and dashboard radii are derived from `arc_radius`: 163 | 164 | ``` r 165 | p + 166 | scale_color_viridis_c( 167 | option = "inferno", 168 | breaks = scales::breaks_pretty(10), 169 | guide = guide_colormeter( 170 | arc_radius = 1.2 171 | ) 172 | ) 173 | ``` 174 | 175 | 176 | 177 | You can use `arc_range` to set the start and end angles of the color 178 | meter, which may yield different shapes: 179 | 180 | ``` r 181 | p + 182 | scale_color_viridis_c( 183 | option = "inferno", 184 | breaks = scales::breaks_pretty(5), # half the arcs 185 | guide = guide_colormeter( 186 | arc_range = c(-pi/2, 0) # quarter circle 187 | ) 188 | ) 189 | ``` 190 | 191 | 192 | 193 | The defaults aren’t great for when you change from the dashboard shape. 194 | Some manual adjustments may be desirable: 195 | 196 | ``` r 197 | p + 198 | scale_color_viridis_c( 199 | option = "inferno", 200 | breaks = scales::breaks_pretty(5), 201 | guide = guide_colormeter( 202 | arc_range = c(-pi/2, 0), 203 | title_position = c(-.2, .2), # moves title left and up from center 204 | legend_padding = grid::unit(0.7, "lines") # pads relative to legend label 205 | ) 206 | ) 207 | ``` 208 | 209 | 210 | 211 | ## 3) Label 212 | 213 | ``` r 214 | formals(guide_colormeter)[grepl("label", names(formals(guide_colormeter)))] 215 | #> $label.theme 216 | #> NULL 217 | #> 218 | #> $label_radius 219 | #> arc_radius * 1.25 220 | ``` 221 | 222 | By default, the dashboard radius is derived from `label_radius`: 223 | 224 | ``` r 225 | p + 226 | scale_color_viridis_c( 227 | option = "inferno", 228 | breaks = scales::breaks_pretty(10), 229 | guide = guide_colormeter( 230 | label_radius = 1.5 231 | ) 232 | ) 233 | ``` 234 | 235 | 236 | 237 | Like `ggplot2::guide_colorsteps()`, the argument `show.limits` controls 238 | labeling the limits of the scale: 239 | 240 | ``` r 241 | p + 242 | scale_color_viridis_c( 243 | option = "inferno", 244 | breaks = scales::breaks_pretty(10), 245 | guide = guide_colormeter( 246 | label_radius = 1.3, 247 | show.limits = TRUE 248 | ) 249 | ) 250 | ``` 251 | 252 | 253 | 254 | ## 4) Dashboard 255 | 256 | ``` r 257 | formals(guide_colormeter)[grepl("dashboard", names(formals(guide_colormeter)))] 258 | #> $dashboard_radius 259 | #> label_radius * 1.2 260 | #> 261 | #> $dashboard_color 262 | #> [1] "black" 263 | #> 264 | #> $dashboard_fill 265 | #> [1] NA 266 | #> 267 | #> $dashboard_linewidth 268 | #> [1] 0.5 269 | #> 270 | #> $dashboard_linetype 271 | #> [1] 1 272 | #> 273 | #> $clip_dashboard 274 | #> [1] TRUE 275 | #> 276 | #> $close_dashboard 277 | #> clip_dashboard 278 | ``` 279 | 280 | `dashboard_radius` controls the radius of just the dashboard circle 281 | 282 | ``` r 283 | p + 284 | scale_color_viridis_c( 285 | option = "inferno", 286 | breaks = scales::breaks_pretty(10), 287 | guide = guide_colormeter( 288 | dashboard_radius = 1.2, 289 | ) 290 | ) 291 | ``` 292 | 293 | 294 | 295 | By default, the dashboard is clipped to the legend boundary, which can 296 | be turned off: 297 | 298 | ``` r 299 | p + 300 | scale_color_viridis_c( 301 | option = "inferno", 302 | breaks = scales::breaks_pretty(10), 303 | guide = guide_colormeter( 304 | title = "mpg

305 | miles per gallon", 306 | clip_dashboard = FALSE 307 | ) 308 | ) + 309 | theme(legend.title = ggtext::element_markdown(vjust = -.6)) 310 | ``` 311 | 312 | 313 | 314 | Non-positional aesthetic arguments for the dashboard: 315 | 316 | ``` r 317 | p + 318 | scale_color_viridis_c( 319 | option = "inferno", 320 | breaks = scales::breaks_pretty(10), 321 | guide = guide_colormeter( 322 | dashboard_fill = "skyblue", 323 | dashboard_color = "steelblue", 324 | dashboard_linetype = 5, 325 | dashboard_linewidth = 4 326 | ) 327 | ) 328 | ``` 329 | 330 | 331 | 332 | ## 5) Frame 333 | 334 | ``` r 335 | formals(guide_colormeter)[grepl("frame", names(formals(guide_colormeter)))] 336 | #> $frame_color 337 | #> [1] NA 338 | #> 339 | #> $frame_linewidth 340 | #> [1] 0.5 341 | #> 342 | #> $frame_linetype 343 | #> [1] 1 344 | ``` 345 | 346 | Frames simply decorate the color arcs/bars: 347 | 348 | ``` r 349 | p + 350 | scale_color_viridis_c( 351 | option = "inferno", 352 | breaks = scales::breaks_pretty(10), 353 | guide = guide_colormeter( 354 | frame_color = "black", 355 | frame_linewidth = .3 356 | ) 357 | ) 358 | ``` 359 | 360 | 361 | 362 | ## Miscellaneous 363 | 364 | Set `debug = TRUE` to inspect the internal legend coordinate system (for 365 | deciding on `dashboard_radius`, `arc_width`, `title_position`, etc.): 366 | 367 | ``` r 368 | p + 369 | scale_color_viridis_c( 370 | option = "inferno", 371 | breaks = scales::breaks_pretty(10), 372 | guide = guide_colormeter(debug = TRUE) 373 | ) 374 | ``` 375 | 376 | 377 | 378 | Puttings labels inside the arc: 379 | 380 | ``` r 381 | p + 382 | scale_color_viridis_c( 383 | option = "inferno", 384 | breaks = scales::breaks_pretty(5), 385 | guide = guide_colormeter( 386 | arc_width = 0.1, 387 | label_radius = .7, 388 | aspect.ratio = 1.1, 389 | dashboard_color = NA 390 | ) 391 | ) + 392 | theme(legend.position = c(.85, .75)) 393 | ``` 394 | 395 | 396 | 397 | ## Acknowledgments 398 | 399 | - Thomas Lin Pedersen for 400 | [`{ggforce}`](https://github.com/thomasp85/ggforce), whose several 401 | unexported functions are used in this package. 402 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://yjunechoe.github.io/ggcolormeter/ 2 | template: 3 | bootstrap: 5 4 | 5 | -------------------------------------------------------------------------------- /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 | ## R CMD check results 2 | 3 | 0 errors | 0 warnings | 1 note 4 | 5 | * This is a new release. 6 | -------------------------------------------------------------------------------- /ggcolormeter.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /man/figures/README-arc-radius-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-arc-radius-1.png -------------------------------------------------------------------------------- /man/figures/README-arc-theme-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-arc-theme-1.png -------------------------------------------------------------------------------- /man/figures/README-simple-usage-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-simple-usage-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-10-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-10-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-11-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-11-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-12-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-12-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-13-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-13-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-14-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-14-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-15-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-15-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-16-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-16-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-17-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-17-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-18-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-18-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-19-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-19-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-2-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-3-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-3-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-4-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-4-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-5-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-5-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-6-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-6-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-7-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-7-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-8-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-8-1.png -------------------------------------------------------------------------------- /man/figures/README-unnamed-chunk-9-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yjunechoe/ggcolormeter/30f5b3a1b9ed66dc91f7ef86d53d99bbffb3c469/man/figures/README-unnamed-chunk-9-1.png -------------------------------------------------------------------------------- /man/guide_colormeter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/guide_colormeter.R 3 | \name{guide_colormeter} 4 | \alias{guide_colormeter} 5 | \title{A color legend in the style of a dashboard meter} 6 | \usage{ 7 | guide_colormeter( 8 | title = ggplot2::waiver(), 9 | title.theme = NULL, 10 | label.theme = NULL, 11 | legend_size = unit(5, "lines"), 12 | legend_padding = unit(c(1.2, 1, 0.3, 1), "lines"), 13 | title_position = c(0, 0), 14 | arc_range = c(-4/7 * pi, 4/7 * pi), 15 | arc_radius = 1, 16 | arc_width = arc_radius/4, 17 | arc_gap = arc_radius/5, 18 | arc_rounding = 0, 19 | label_radius = arc_radius * 1.25, 20 | dashboard_radius = label_radius * 1.2, 21 | dashboard_color = "black", 22 | dashboard_fill = NA, 23 | dashboard_linewidth = 0.5, 24 | dashboard_linetype = 1, 25 | clip_dashboard = TRUE, 26 | close_dashboard = clip_dashboard, 27 | frame_color = NA, 28 | frame_linewidth = 0.5, 29 | frame_linetype = 1, 30 | aspect.ratio = 1, 31 | show.limits = NULL, 32 | debug = FALSE, 33 | reverse = FALSE, 34 | available_aes = c("colour", "color", "fill"), 35 | ... 36 | ) 37 | } 38 | \arguments{ 39 | \item{title}{A character string or expression indicating a title of guide. 40 | If \code{NULL}, the title is not shown. By default 41 | (\code{\link[ggplot2:waiver]{waiver()}}), the name of the scale object or the name 42 | specified in \code{\link[ggplot2:labs]{labs()}} is used for the title.} 43 | 44 | \item{title.theme}{A theme object for rendering the title text. Usually the 45 | object of \code{\link[ggplot2:element_text]{element_text()}} is expected. By default, the theme is 46 | specified by \code{legend.title} in \code{\link[ggplot2:theme]{theme()}} or theme.} 47 | 48 | \item{label.theme}{A theme object for rendering the label text. Usually the 49 | object of \code{\link[ggplot2:element_text]{element_text()}} is expected. By default, the theme is 50 | specified by \code{legend.text} in \code{\link[ggplot2:theme]{theme()}}.} 51 | 52 | \item{legend_size}{Size of the legend box.} 53 | 54 | \item{legend_padding}{Spacing between the color meter and the legend boundary.} 55 | 56 | \item{title_position}{<\code{\link{legend-coords}}> 2-length vector for the x/y-position of the legend title.} 57 | 58 | \item{arc_range}{<\code{\link{legend-coords}}> 2-length vector for the start and end angles of the color meter.} 59 | 60 | \item{arc_radius}{<\code{\link{legend-coords}}> Radius of the color meter.} 61 | 62 | \item{arc_width}{<\code{\link{legend-coords}}> Width of the arcs in the color meter.} 63 | 64 | \item{arc_gap}{<\code{\link{legend-coords}}> Gap between arcs in the color meter.} 65 | 66 | \item{arc_rounding}{<\code{\link{legend-coords}}> Rounding of arcs in the color meter.} 67 | 68 | \item{label_radius}{<\code{\link{legend-coords}}> Radius of the labels.} 69 | 70 | \item{dashboard_radius}{<\code{\link{legend-coords}}> Radius of the dashboard background.} 71 | 72 | \item{dashboard_color}{Dashboard background color.} 73 | 74 | \item{dashboard_fill}{Dashboard background fill.} 75 | 76 | \item{dashboard_linewidth}{Dashboard background line width.} 77 | 78 | \item{dashboard_linetype}{Dashboard background line type.} 79 | 80 | \item{clip_dashboard}{Whether the dashboard circle should clip to the legend boundary.} 81 | 82 | \item{close_dashboard}{Whether the dashboard should be closed where it meets the legend boundary.} 83 | 84 | \item{frame_color}{Color of the frame drawn around the arcs.} 85 | 86 | \item{frame_linewidth}{Width of the frame drawn around the arcs.} 87 | 88 | \item{frame_linetype}{Line type of the frame drawn around the arcs.} 89 | 90 | \item{aspect.ratio}{Aspect ratio for the legend.} 91 | 92 | \item{show.limits}{Logical. Should the limits of the scale be shown with 93 | labels and ticks. Default is \code{NULL} meaning it will take the value from the 94 | scale. This argument is ignored if \code{labels} is given as a vector of 95 | values. If one or both of the limits is also given in \code{breaks} it will be 96 | shown irrespective of the value of \code{show.limits}.} 97 | 98 | \item{debug}{If \code{TRUE}, axes and origin for <\code{\link{legend-coords}}> are drawn over the legend for debugging.} 99 | 100 | \item{reverse}{logical. If \code{TRUE} the colourbar is reversed. By default, 101 | the highest value is on the top and the lowest value is on the bottom} 102 | 103 | \item{available_aes}{A vector of character strings listing the aesthetics 104 | for which a colourbar can be drawn.} 105 | 106 | \item{...}{Ignored.} 107 | } 108 | \value{ 109 | A guide object of class 'colormeter' 110 | } 111 | \description{ 112 | A color legend in the style of a dashboard meter 113 | } 114 | \examples{ 115 | library(ggplot2) 116 | # A standard plot 117 | p <- ggplot(mtcars, aes(drat, hp)) + 118 | geom_point(aes(color = mpg)) 119 | # Colormeter guide for color scale 120 | p + 121 | scale_color_viridis_c( 122 | option = "inferno", 123 | breaks = scales::breaks_pretty(10), 124 | guide = guide_colormeter() 125 | ) 126 | 127 | } 128 | -------------------------------------------------------------------------------- /man/legend-coords.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/guide_colormeter.R 3 | \name{legend-coords} 4 | \alias{legend-coords} 5 | \title{Colormeter legend coordinate system} 6 | \description{ 7 | Due to the peculiar nature of the colormeter legend (e.g., dynamic size and positioning 8 | of color bars/arcs depending on the number of breaks), many parts of the legend are drawn in a 9 | mini isolated coordinate space. You can inspect this coordinate space with \code{debug = TRUE}. 10 | 11 | The coordinate space defaults to the x-y range of the legend "data", which considers the 12 | polar-transformed positioning of the color arcs/bars, the labels, and the dashboard circle. 13 | } 14 | \examples{ 15 | library(ggplot2) 16 | # A standard plot 17 | p <- ggplot(mtcars, aes(drat, hp)) + 18 | geom_point(aes(color = mpg)) 19 | # Colormeter guide for color scale 20 | p + 21 | scale_color_viridis_c( 22 | option = "inferno", 23 | breaks = scales::breaks_pretty(10), 24 | guide = guide_colormeter(debug = TRUE) 25 | ) 26 | } 27 | \keyword{internal} 28 | --------------------------------------------------------------------------------