├── R
├── sysdata.rda
├── colors_race.R
├── position_nudge_repel.R
├── colors_highlight.R
├── colors_continuous.R
├── axis_handling.R
├── colors_discrete.R
├── RcppExports.R
├── cmapplot.R
├── default_aes.R
├── data.R
└── utilities.R
├── LICENSE
├── data
├── peer_grp.rda
├── economy_basic.rda
├── grp_over_time.rda
├── cluster_jobchange.rda
├── percentile_wages.rda
├── transit_ridership.rda
├── vehicle_ownership.rda
├── traded_emp_by_race.rda
└── pop_and_laborforce_by_age.rda
├── man
├── figures
│ ├── logo.png
│ ├── margins.pptx
│ ├── margins1.png
│ ├── margins2.png
│ ├── logo_notext.png
│ ├── README-theme-1.png
│ └── README-finalize-1.png
├── peer_grp.Rd
├── percentile_wages.Rd
├── transit_ridership.Rd
├── grp_over_time.Rd
├── cluster_jobchange.Rd
├── pop_and_laborforce_by_age.Rd
├── vehicle_ownership.Rd
├── economy_basic.Rd
├── traded_emp_by_race.Rd
├── cmapplot.Rd
├── cmap_fill_continuous.Rd
├── cmap_fill_discrete.Rd
├── customproto.Rd
├── cmap_fill_race.Rd
├── update_recessions.Rd
├── position_nudge_repel.Rd
├── dot-lwd.Rd
├── abbr_years.Rd
├── viz_palette.Rd
├── cmap_default_aes.Rd
├── cmap_fill_highlight.Rd
├── get_cmapplot_globals.Rd
├── theme_cmap.Rd
├── geom_pandemics.Rd
├── geom_text_lastonly.Rd
├── finalize_plot.Rd
├── geom_recessions.Rd
└── geom_text_lastonly_repel.Rd
├── pkgdown
├── favicon
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── apple-touch-icon.png
│ ├── apple-touch-icon-120x120.png
│ ├── apple-touch-icon-152x152.png
│ ├── apple-touch-icon-180x180.png
│ ├── apple-touch-icon-60x60.png
│ └── apple-touch-icon-76x76.png
└── _pkgdown.yml
├── .gitignore
├── .Rbuildignore
├── cmapplot.Rproj
├── LICENSE.md
├── DESCRIPTION
├── NAMESPACE
├── vignettes
├── installation.Rmd
├── colors.Rmd
├── plots.Rmd
└── finalize.Rmd
├── .github
└── workflows
│ ├── check-standard.yaml
│ └── pkgdown.yaml
├── README.Rmd
├── README.md
└── NEWS.md
/R/sysdata.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/R/sysdata.rda
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | YEAR: 2020
2 | COPYRIGHT HOLDER: Chicago Metropolitan Agency for Planning
3 |
--------------------------------------------------------------------------------
/data/peer_grp.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/peer_grp.rda
--------------------------------------------------------------------------------
/man/figures/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/logo.png
--------------------------------------------------------------------------------
/data/economy_basic.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/economy_basic.rda
--------------------------------------------------------------------------------
/data/grp_over_time.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/grp_over_time.rda
--------------------------------------------------------------------------------
/man/figures/margins.pptx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/margins.pptx
--------------------------------------------------------------------------------
/man/figures/margins1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/margins1.png
--------------------------------------------------------------------------------
/man/figures/margins2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/margins2.png
--------------------------------------------------------------------------------
/data/cluster_jobchange.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/cluster_jobchange.rda
--------------------------------------------------------------------------------
/data/percentile_wages.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/percentile_wages.rda
--------------------------------------------------------------------------------
/data/transit_ridership.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/transit_ridership.rda
--------------------------------------------------------------------------------
/data/vehicle_ownership.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/vehicle_ownership.rda
--------------------------------------------------------------------------------
/data/traded_emp_by_race.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/traded_emp_by_race.rda
--------------------------------------------------------------------------------
/man/figures/logo_notext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/logo_notext.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/favicon.ico
--------------------------------------------------------------------------------
/man/figures/README-theme-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/README-theme-1.png
--------------------------------------------------------------------------------
/data/pop_and_laborforce_by_age.rda:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/data/pop_and_laborforce_by_age.rda
--------------------------------------------------------------------------------
/man/figures/README-finalize-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/man/figures/README-finalize-1.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/pkgdown/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/pkgdown/favicon/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CMAP-REPOS/cmapplot/HEAD/pkgdown/favicon/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .DS_Store
5 | inst/doc
6 | docs
7 | doc
8 | Meta
9 | Rplots.pdf
10 | vignettes/*.png
11 | /doc/
12 | /Meta/
13 |
--------------------------------------------------------------------------------
/.Rbuildignore:
--------------------------------------------------------------------------------
1 | ^cmapplot\.Rproj$
2 | ^\.Rproj\.user$
3 | ^LICENSE\.md$
4 | ^README\.Rmd$
5 | ^\.github$
6 | ^_pkgdown\.yml$
7 | ^docs$
8 | ^pkgdown$
9 | ^doc$
10 | ^Meta$
11 | [.]pptx$
12 | ^Rplots.pdf$
13 |
--------------------------------------------------------------------------------
/cmapplot.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 | ProjectId: 4fa506ff-d1f7-44a2-9c57-2d8d7beb1fa7
3 |
4 | RestoreWorkspace: No
5 | SaveWorkspace: No
6 | AlwaysSaveHistory: Default
7 |
8 | EnableCodeIndexing: Yes
9 | UseSpacesForTab: Yes
10 | NumSpacesForTab: 2
11 | Encoding: UTF-8
12 |
13 | RnwWeave: Sweave
14 | LaTeX: pdfLaTeX
15 |
16 | AutoAppendNewline: Yes
17 | StripTrailingWhitespace: Yes
18 | LineEndingConversion: Windows
19 |
20 | BuildType: Package
21 | PackageUseDevtools: Yes
22 | PackageInstallArgs: --no-multiarch --with-keep.source
23 | PackageRoxygenize: rd,collate,namespace
24 |
--------------------------------------------------------------------------------
/man/peer_grp.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{peer_grp}
5 | \alias{peer_grp}
6 | \title{Gross Regional Product by region, with peers, 2001-17}
7 | \format{
8 | A tibble. 121 rows and 5 variables:
9 | \describe{
10 | \item{area}{Factor. name of the region}
11 | \item{year}{Double. year of the data}
12 | \item{grp}{Double. real gross regional product}
13 | }
14 | }
15 | \source{
16 | CMAP traded clusters report
17 | }
18 | \usage{
19 | peer_grp
20 | }
21 | \description{
22 | A test dataset containing real GRP data for the CMAP and peer regions.
23 | }
24 | \examples{
25 | # a time-series line chart
26 | ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
27 | geom_line()
28 |
29 | }
30 | \keyword{datasets}
31 |
--------------------------------------------------------------------------------
/man/percentile_wages.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{percentile_wages}
5 | \alias{percentile_wages}
6 | \title{Wage percentiles by cluster}
7 | \format{
8 | A tibble. 45 rows and 3 variables:
9 | \describe{
10 | \item{cluster}{Chr. The name of the cluster}
11 | \item{percentile}{Double. The percentile wage being reported}
12 | \item{wage}{Double. The wage. I believe 2017 data.}
13 | }
14 | }
15 | \source{
16 | CMAP traded clusters report
17 | }
18 | \usage{
19 | percentile_wages
20 | }
21 | \description{
22 | A test dataset containing the 10th, 25th, 50th, 75th, and 90th percentile wage by cluster in the CMAP region.
23 | }
24 | \examples{
25 | # a non-time-series line chart
26 | ggplot(percentile_wages, aes(x = percentile, y = wage, color = cluster)) +
27 | geom_line()
28 |
29 | }
30 | \keyword{datasets}
31 |
--------------------------------------------------------------------------------
/man/transit_ridership.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{transit_ridership}
5 | \alias{transit_ridership}
6 | \title{Transit ridership in the Chicago region, 1980-2024}
7 | \format{
8 | A tibble. 225 rows and 3 variables
9 | \describe{
10 | \item{year}{Double. Year of data}
11 | \item{system}{Char. Name of system (includes CTA bus, CTA rail, Metra, Pace, and Pace ADA)}
12 | \item{ridership}{Double. Annual unlinked passenger trips in millions}
13 | }
14 | }
15 | \source{
16 | Regional Transportation Authority \url{http://www.rtams.org/rtams/systemRidership.jsp}
17 | }
18 | \usage{
19 | transit_ridership
20 | }
21 | \description{
22 | A test dataset containing 1980-2019 transit ridership for the three service
23 | boards that provide transit in Northeastern Illinois.
24 | }
25 | \examples{
26 | # A line graph
27 | ggplot(transit_ridership,aes(x = year,y=ridership,group=system,color=system)) +
28 | geom_line(na.rm=TRUE)
29 |
30 |
31 | }
32 | \keyword{datasets}
33 |
--------------------------------------------------------------------------------
/man/grp_over_time.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{grp_over_time}
5 | \alias{grp_over_time}
6 | \title{Gross Regional Product by cluster, 2007-17}
7 | \format{
8 | A tibble. 121 rows and 5 variables:
9 | \describe{
10 | \item{cluster}{Chr. The name of the cluster}
11 | \item{category}{Factor. "goods-producing" or "services"}
12 | \item{assessment}{Factor. "Trailing", "Mixed", or "Leading"}
13 | \item{year}{Double. The year of the data}
14 | \item{realgrp}{Double. The real gross regional product of the cluster in year `year`.
15 | Not exactly sure on the inflation year but I believe it is 2012}
16 | }
17 | }
18 | \source{
19 | CMAP traded clusters report
20 | }
21 | \usage{
22 | grp_over_time
23 | }
24 | \description{
25 | A test dataset containing real GRP data for the CMAP region.
26 | }
27 | \examples{
28 | # a time-series line chart
29 | ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
30 | geom_line()
31 |
32 | }
33 | \keyword{datasets}
34 |
--------------------------------------------------------------------------------
/man/cluster_jobchange.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{cluster_jobchange}
5 | \alias{cluster_jobchange}
6 | \title{Job change in CMAP region by cluster, 2001-17}
7 | \format{
8 | A tibble. 22 rows and 5 variables:
9 | \describe{
10 | \item{code}{Integer. code of cluster}
11 | \item{name}{Char. textual description/cluster title}
12 | \item{category}{Factor. Either "goods-producing" or "services"}
13 | \item{assessment}{Factor. "Leading", "Mixed", or "Trailing"}
14 | \item{jobchange}{Integer. Total change in employment in the cluster between 2001-17}
15 | }
16 | }
17 | \source{
18 | CMAP traded clusters report
19 | }
20 | \usage{
21 | cluster_jobchange
22 | }
23 | \description{
24 | A test dataset containing 2001-17 job change and other data for the 22 specialized traded clusters
25 | analyzed in the CMAP Traded Clusters report.
26 | }
27 | \examples{
28 | # A bar chart
29 | ggplot(cluster_jobchange, aes(x = reorder(name, jobchange), y = jobchange, fill = category)) +
30 | geom_col() +
31 | coord_flip()
32 |
33 |
34 | }
35 | \keyword{datasets}
36 |
--------------------------------------------------------------------------------
/man/pop_and_laborforce_by_age.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{pop_and_laborforce_by_age}
5 | \alias{pop_and_laborforce_by_age}
6 | \title{Population and Labor Force by Age}
7 | \format{
8 | A tibble. 12 rows and 4 variables:
9 | \describe{
10 | \item{variable}{Chr. Indicates the meaning of the data stored in `value`. "population" or "laborforce".}
11 | \item{year}{Factor. 2010 or 2017.}
12 | \item{age}{Chr. The age bucket. Either 16-24, 25-54, or 55+.}
13 | \item{value}{Double. The value indicated by the other variables.}
14 | }
15 | }
16 | \source{
17 | CMAP traded clusters report
18 | }
19 | \usage{
20 | pop_and_laborforce_by_age
21 | }
22 | \description{
23 | A test dataset containing percentage breakdowns of the population and labor force by various age buckets in 2010 and 2017.
24 | }
25 | \examples{
26 | # a grouped and stacked bar chart (via `interaction()`)
27 | ggplot(pop_and_laborforce_by_age, aes(x = interaction(year, variable), y = value, fill = age)) +
28 | geom_col(position = position_stack(reverse = TRUE))
29 |
30 | }
31 | \keyword{datasets}
32 |
--------------------------------------------------------------------------------
/man/vehicle_ownership.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{vehicle_ownership}
5 | \alias{vehicle_ownership}
6 | \title{Vehicle ownership in the CMAP seven county region}
7 | \format{
8 | A tibble. 40 rows and 3 variables
9 | \describe{
10 | \item{county}{Char. Name of county}
11 | \item{number_of_veh}{Char. Number of vehicles owned by household}
12 | \item{pct}{Numeric. Share of households with the given number of vehicles (values between 0 and 1)}
13 | }
14 | }
15 | \source{
16 | CMAP Travel Inventory Survey Data Summary \url{https://www.cmap.illinois.gov/documents/10180/77659/Travel+Inventory+Survey+Data+Summary_weighted_V2.pdf/d4b33cdd-1c44-4322-b32f-2f54b85207cb}
17 | }
18 | \usage{
19 | vehicle_ownership
20 | }
21 | \description{
22 | A test dataset containing vehicle ownership rates in the seven county region
23 | of northeastern Illinois.
24 | }
25 | \examples{
26 | # A stacked bar chart
27 | ggplot(vehicle_ownership,
28 | aes(x = county, y = pct, fill = number_of_veh)) +
29 | geom_bar(position = position_stack(), stat = "identity")
30 |
31 | }
32 | \keyword{datasets}
33 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2020 Chicago Metropolitan Agency for Planning
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 |
--------------------------------------------------------------------------------
/man/economy_basic.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{economy_basic}
5 | \alias{economy_basic}
6 | \title{Basic regional economic stats in 2001 and 2017}
7 | \format{
8 | A tibble. 18 rows and 4 variables:
9 | \describe{
10 | \item{variable}{Chr. Indicates the meaning of the data stored in `value`. Jobs, Real Earnings, or Establishments.}
11 | \item{year}{Factor. 2001 or 2017.}
12 | \item{sector}{Chr. local, tradedgoods, or tradedservices. Together, these three sectors account for all clusters in the region.}
13 | \item{value}{Int. The value indicated as described by the other columns}
14 | }
15 | }
16 | \source{
17 | CMAP traded clusters report
18 | }
19 | \usage{
20 | economy_basic
21 | }
22 | \description{
23 | A test dataset containing count of jobs, earnings, and establishments in the Chicago region in both 2001 and 2017.
24 | }
25 | \examples{
26 | # a grouped and stacked bar chart (via `interaction()`)
27 | ggplot(economy_basic, aes(x = interaction(year, variable), y = value, fill = sector)) +
28 | geom_col(position = "fill") +
29 | scale_y_continuous(labels = scales::percent)
30 |
31 | }
32 | \keyword{datasets}
33 |
--------------------------------------------------------------------------------
/man/traded_emp_by_race.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/data.R
3 | \docType{data}
4 | \name{traded_emp_by_race}
5 | \alias{traded_emp_by_race}
6 | \title{Traded employment by race}
7 | \format{
8 | A tibble. 12 rows and 4 variables:
9 | \describe{
10 | \item{Race}{Chr. White, Asian, Hispanic, Other, Black, or Regional Average.}
11 | \item{variable}{Chr. SpecializedTraded, UnspecializedTraded, or Total.
12 | Total is a sum of SpecializedTraded and UnspecializedTraded. The invisible remainder (e.g. `1-Total` or
13 | `1-(SpecializedTraded+UnspecializedTraded)`) is the percentage employed in local clusters.}
14 | \item{value}{Double. The value indicated by the other variables.}
15 | }
16 | }
17 | \source{
18 | CMAP traded clusters report
19 | }
20 | \usage{
21 | traded_emp_by_race
22 | }
23 | \description{
24 | A test dataset containing the percentage breakdowns of the working population employed in traded clusters, by race.
25 | }
26 | \examples{
27 | # a stacked bar chart
28 | \dontshow{library(dplyr)}
29 | df <- dplyr::filter(
30 | traded_emp_by_race,
31 | variable \%in\% c("SpecializedTraded", "UnspecializedTraded")
32 | )
33 | ggplot(df, aes(x = reorder(Race, -value), y = value, fill = variable)) +
34 | geom_col(position = position_stack(reverse = TRUE)) +
35 | scale_y_continuous(labels = scales::percent)
36 |
37 | }
38 | \keyword{datasets}
39 |
--------------------------------------------------------------------------------
/man/cmapplot.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/cmapplot.R
3 | \docType{package}
4 | \name{cmapplot}
5 | \alias{cmapplot-package}
6 | \alias{cmapplot}
7 | \title{cmapplot}
8 | \description{
9 | This package contains extra palettes, themes and geoms for \pkg{ggplot2},
10 | based on Chicago Metropolitan Agency for Planning (CMAP) design guidelines.
11 | }
12 | \details{
13 | Detailed documentation can be viewed at
14 | \url{https://cmap-repos.github.io/cmapplot}.
15 |
16 | Please report issues and suggest improvements at
17 | \url{https://github.com/CMAP-REPOS/cmapplot/issues}.
18 | }
19 | \seealso{
20 | Useful links:
21 | \itemize{
22 | \item \url{https://cmap-repos.github.io/cmapplot}
23 | \item \url{https://github.com/CMAP-REPOS/cmapplot}
24 | \item Report bugs at \url{https://github.com/CMAP-REPOS/cmapplot/issues}
25 | }
26 |
27 | }
28 | \author{
29 | \strong{Maintainer}: Sean Connelly \email{sconnelly@cmap.illinois.gov}
30 |
31 | Authors:
32 | \itemize{
33 | \item Daniel Comeaux (\href{https://orcid.org/0000-0002-8412-9092}{ORCID})
34 | \item Sarah Buchhorn
35 | \item Martin Menninger \email{mmenninger@cmap.illinois.gov}
36 | \item Noel Peterson (\href{https://orcid.org/0000-0003-1290-2362}{ORCID})
37 | \item Greta Ritzenthaler
38 | \item Matthew Stern (\href{https://orcid.org/0000-0001-9119-2121}{ORCID})
39 | \item David Wells \email{dwells@cmap.illinois.gov}
40 | }
41 |
42 | Other contributors:
43 | \itemize{
44 | \item Chicago Metropolitan Agency for Planning [copyright holder, funder]
45 | }
46 |
47 | }
48 | \keyword{internal}
49 |
--------------------------------------------------------------------------------
/man/cmap_fill_continuous.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/colors_continuous.R
3 | \name{cmap_fill_continuous}
4 | \alias{cmap_fill_continuous}
5 | \alias{cmap_color_continuous}
6 | \alias{cmap_colour_continuous}
7 | \title{Apply continuous CMAP palettes (gradients) to ggplot2 aesthetics}
8 | \usage{
9 | cmap_fill_continuous(palette = "blues", reverse = FALSE, middle = 0, ...)
10 |
11 | cmap_color_continuous(palette = "blues", reverse = FALSE, middle = 0, ...)
12 |
13 | cmap_colour_continuous(palette = "blues", reverse = FALSE, middle = 0, ...)
14 | }
15 | \arguments{
16 | \item{palette}{String; Choose from 'cmap_gradients' list}
17 |
18 | \item{reverse}{Logical; Reverse color order?}
19 |
20 | \item{middle}{Numeric; Sets midpoint for diverging color palettes. Default =
21 | 0.}
22 |
23 | \item{...}{Additional parameters passed on to the scale type}
24 | }
25 | \description{
26 | Pick the function depending on the aesthetic of your ggplot object (fill or
27 | color). On diverging palettes, a midpoint can be manually adjusted (defaults
28 | to 0). See \code{\link{cmap_gradients}} for a listing of available gradients.
29 | }
30 | \section{Functions}{
31 | \itemize{
32 | \item \code{cmap_fill_continuous()}: for fill aesthetic
33 |
34 | \item \code{cmap_color_continuous()}: for color aesthetic
35 |
36 | \item \code{cmap_colour_continuous()}: for color aesthetic
37 |
38 | }}
39 | \examples{
40 | ggplot(dplyr::filter(grp_over_time, cluster=="Biopharmaceuticals"),
41 | aes(x = year, y = realgrp, color = realgrp)) +
42 | geom_line() +
43 | cmap_color_continuous(palette = "red_purple")
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/man/cmap_fill_discrete.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/colors_discrete.R
3 | \name{cmap_fill_discrete}
4 | \alias{cmap_fill_discrete}
5 | \alias{cmap_color_discrete}
6 | \alias{cmap_colour_discrete}
7 | \title{Apply discrete CMAP palettes to ggplot2 aesthetics}
8 | \usage{
9 | cmap_fill_discrete(palette = "main", reverse = FALSE, ...)
10 |
11 | cmap_color_discrete(palette = "main", reverse = FALSE, ...)
12 |
13 | cmap_colour_discrete(palette = "main", reverse = FALSE, ...)
14 | }
15 | \arguments{
16 | \item{palette}{Choose from 'cmap_palettes' list, or use one of the gradients
17 | defined in the 'cmap_gradients' list (gradients will be automatically
18 | converted into discrete bins)}
19 |
20 | \item{reverse}{Logical; reverse color order?}
21 |
22 | \item{...}{Additional parameters passed on to the scale type}
23 | }
24 | \description{
25 | Pick the function depending on the aesthetic of your ggplot object (fill or
26 | color). See \code{link{cmap_palettes}} for a listing of available gradients.
27 | }
28 | \section{Functions}{
29 | \itemize{
30 | \item \code{cmap_fill_discrete()}: For fill aesthetic
31 |
32 | \item \code{cmap_color_discrete()}: For color aesthetic
33 |
34 | \item \code{cmap_colour_discrete()}: For color aesthetic
35 |
36 | }}
37 | \examples{
38 | ggplot(pop_and_laborforce_by_age, aes(x = variable, y = value, fill = age)) +
39 | geom_col(position = position_stack(reverse = TRUE)) +
40 | facet_wrap(~year) +
41 | cmap_fill_discrete(palette = "community")
42 |
43 | ggplot(percentile_wages, aes(x = percentile, y = wage, color = cluster)) +
44 | geom_line() +
45 | cmap_color_discrete(palette = "prosperity")
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/pkgdown/_pkgdown.yml:
--------------------------------------------------------------------------------
1 | url: https://cmap-repos.github.io/cmapplot
2 |
3 | home:
4 | title: CMAP Themes and Color Palettes
5 | description: >
6 | Provides themes and color scales for 'ggplot2', based on Chicago
7 | Metropolitan Agency for Planning (CMAP) design guidelines.
8 |
9 | authors:
10 | Chicago Metropolitan Agency for Planning:
11 | href: https://www.cmap.illinois.gov
12 | html: >
13 |
15 |
16 | template:
17 | params:
18 | bootswatch: flatly
19 |
20 | reference:
21 | - title: Key functions
22 | - contents:
23 | - theme_cmap
24 | - finalize_plot
25 | - title: Additional geoms & auxiliary functions
26 | - contents:
27 | - starts_with("geom_")
28 | - ends_with("cmap_default_aes")
29 | - abbr_years
30 | - title: Color palettes & gradients
31 | - contents:
32 | - starts_with("viz_")
33 | - starts_with("cmap_fill_")
34 | - title: Sample datasets
35 | - contents:
36 | - cluster_jobchange
37 | - economy_basic
38 | - peer_grp
39 | - grp_over_time
40 | - percentile_wages
41 | - pop_and_laborforce_by_age
42 | - traded_emp_by_race
43 | - transit_ridership
44 | - vehicle_ownership
45 | - title: Lesser used objects
46 | - contents:
47 | - contains("cmapplot_global")
48 | - gg_lwd_convert
49 | - update_recessions
50 | - customproto
51 |
52 | articles:
53 | - title: Articles
54 | navbar: ~
55 | contents:
56 | - installation
57 | - plots
58 | - finalize
59 | - colors
60 | - cookbook
61 |
62 | resource_files:
63 | - man/figures/margins1.png
64 | - man/figures/margins2.png
65 |
--------------------------------------------------------------------------------
/man/customproto.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geom_pandemics.R, R/geom_recessions.R,
3 | % R/geom_text_lastonly.R, R/geom_text_lastonly_repel.R
4 | \docType{data}
5 | \name{customproto}
6 | \alias{customproto}
7 | \alias{GeomPandemics}
8 | \alias{GeomPandemicsText}
9 | \alias{GeomRecessions}
10 | \alias{GeomRecessionsText}
11 | \alias{GeomTextLast}
12 | \alias{GeomPointLast}
13 | \alias{GeomTextLastRepel}
14 | \title{Custom ggproto classes}
15 | \description{
16 | The \code{cmapplot} package contains a few custom ggproto objects. For the
17 | most part, these are slightly tweaked versions of ggplot2's default proto
18 | objects. For more information about these, see
19 | \code{\link[ggplot2:ggplot2-ggproto]{ggplot2::ggplot2-ggproto}}.
20 |
21 | The \code{cmapplot} package contains a few custom ggproto objects. For the
22 | most part, these are slightly tweaked versions of ggplot2's default proto
23 | objects. For more information about these, see
24 | \code{\link[ggplot2:ggplot2-ggproto]{ggplot2::ggplot2-ggproto}}.
25 | }
26 | \section{Functions}{
27 | \itemize{
28 | \item \code{GeomPandemics}: Add Pandemic bars to plot.
29 |
30 | \item \code{GeomPandemicsText}: Add Pandemic bar labels to plot.
31 |
32 | \item \code{GeomRecessions}: Add recession bars to plot.
33 |
34 | \item \code{GeomRecessionsText}: Add recession bar labels to plot.
35 |
36 | \item \code{GeomTextLast}: Add text to plot for maximum x-value in dataset only.
37 |
38 | \item \code{GeomPointLast}: Add points to plot for maximum x-value in dataset only.
39 |
40 | \item \code{GeomTextLastRepel}: Add text to plot for maximum x-value in dataset only.
41 |
42 | \item \code{GeomPointLast}: Add points to plot for maximum x-value in dataset only.
43 |
44 | }}
45 | \keyword{datasets}
46 |
--------------------------------------------------------------------------------
/man/cmap_fill_race.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/colors_race.R
3 | \name{cmap_fill_race}
4 | \alias{cmap_fill_race}
5 | \alias{cmap_color_race}
6 | \alias{cmap_colour_race}
7 | \title{Apply official CMAP race/ethnicity chart colors to ggplot2 aesthetics}
8 | \usage{
9 | cmap_fill_race(white, black, hispanic, asian, other)
10 |
11 | cmap_color_race(white, black, hispanic, asian, other)
12 |
13 | cmap_colour_race(white, black, hispanic, asian, other)
14 | }
15 | \arguments{
16 | \item{white}{Data value to map CMAP's White/Caucasian color onto (case-sensitive).}
17 |
18 | \item{black}{Data value to map CMAP's Black/African American color onto (case-sensitive).}
19 |
20 | \item{hispanic}{Data value to map CMAP's Hispanic/Latino color onto (case-sensitive).}
21 |
22 | \item{asian}{Data value to map CMAP's Asian color onto (case-sensitive).}
23 |
24 | \item{other}{Data value to map CMAP's Other/Multiple Races color onto (case-sensitive).}
25 | }
26 | \description{
27 | Pick the function depending on the aesthetic of your ggplot object (fill or color).
28 | Specify your dataset's unique race factor names (as case-sensitive strings) in the arguments.
29 | All categories are optional in case your dataset does not have some of them or contains the default
30 | values of the race palette.
31 | }
32 | \section{Functions}{
33 | \itemize{
34 | \item \code{cmap_fill_race()}: For fill aesthetic
35 |
36 | \item \code{cmap_color_race()}: For color aesthetic
37 |
38 | \item \code{cmap_colour_race()}: For color aesthetic
39 |
40 | }}
41 | \examples{
42 | ggplot(dplyr::filter(traded_emp_by_race, Race!="Regional average" &
43 | variable=="SpecializedTraded")) +
44 | geom_col(aes(x = Race, y = value, fill = Race)) +
45 | cmap_fill_race(white = "White", black = "Black",
46 | hispanic = "Hispanic", asian = "Asian",
47 | other = "Other")
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/man/update_recessions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geom_recessions.R
3 | \name{update_recessions}
4 | \alias{update_recessions}
5 | \title{Update recessions table}
6 | \source{
7 | \url{https://www.nber.org/data/cycles/cycle dates pasted.csv}
8 | }
9 | \usage{
10 | update_recessions(url = NULL, quietly = FALSE)
11 | }
12 | \arguments{
13 | \item{url}{Char, the web location of the NBER machine-readable CSV file. The
14 | default, \code{NULL}, uses the most recently identified URL known to the
15 | package development team, which appears to be the most stable location for
16 | updates over time.}
17 |
18 | \item{quietly}{Logical, suppresses messages produced by
19 | \code{utils::download.file}.}
20 | }
21 | \value{
22 | A data frame with the following variables: \itemize{ \item
23 | \code{start_char, end_char}: Chr. Easily readable labels for the beginning
24 | and end of the recession. \item \code{start_date, end_date}: Date. Dates
25 | expressed in R datetime format, using the first day of the specified month.
26 | \item \code{ongoing}: Logical. Whether or not the recession is ongoing as of
27 | the latest available NBER data. }
28 | }
29 | \description{
30 | The cmapplot package contains an internal dataset \code{recessions} of all
31 | recessions in American history as recorded by the National Bureau of Economic
32 | Research (NBER). However, users may need to replace the built-in data, such as
33 | in the event of new recessions and/or changes to the NBER consensus on
34 | recession dates. This function fetches and interprets this data from the NBER
35 | website.
36 | }
37 | \examples{
38 | recessions <- update_recessions()
39 |
40 | # package maintainers can update the internal dataset from within
41 | # package by running the following code:
42 | \dontrun{
43 | recessions <- update_recessions()
44 | usethis::use_data(recessions, internal = TRUE, overwrite = TRUE)
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/man/position_nudge_repel.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/position_nudge_repel.R
3 | \name{position_nudge_repel}
4 | \alias{position_nudge_repel}
5 | \title{Position Nudge Repel}
6 | \arguments{
7 | \item{x, y}{Amount of horizontal and vertical distance to move. Same units
8 | as the data on the x and y axes.}
9 | }
10 | \description{
11 | Nudge labels a fixed distance from points
12 | }
13 | \details{
14 | \code{position_nudge_repel} is useful for adjusting the starting
15 | position of text labels before they are repelled from data points.
16 | }
17 | \examples{
18 |
19 | library(ggrepel)
20 |
21 | df <- data.frame(
22 | x = c(1,3,2,5),
23 | y = c("a","c","d","c")
24 | )
25 |
26 | ggplot(df, aes(x, y)) +
27 | geom_point() +
28 | geom_text_repel(aes(label = y))
29 |
30 | ggplot(df, aes(x, y)) +
31 | geom_point() +
32 | geom_text_repel(
33 | aes(label = y),
34 | min.segment.length = 0,
35 | position = position_nudge_repel(x = 0.1, y = 0.15)
36 | )
37 |
38 | # The values for x and y can be vectors
39 | ggplot(df, aes(x, y)) +
40 | geom_point() +
41 | geom_text_repel(
42 | aes(label = y),
43 | min.segment.length = 0,
44 | position = position_nudge_repel(
45 | x = c(0.1, 0, -0.1, 0),
46 | y = c(0.1, 0.2, -0.1, -0.2)
47 | )
48 | )
49 |
50 | # We can also use geom_text_repel() with arguments nudge_x, nudge_y
51 | ggplot(df, aes(x, y)) +
52 | geom_point() +
53 | geom_text_repel(
54 | aes(label = y),
55 | min.segment.length = 0,
56 | nudge_x = 0.1,
57 | nudge_y = 0.15
58 | )
59 |
60 | # The arguments nudge_x, nudge_y also accept vectors
61 | ggplot(df, aes(x, y)) +
62 | geom_point() +
63 | geom_text_repel(
64 | aes(label = y),
65 | min.segment.length = 0,
66 | nudge_x = c(0.1, 0, -0.1, 0),
67 | nudge_y = c(0.1, 0.2, -0.1, -0.2)
68 | )
69 |
70 | }
71 | \concept{position adjustments}
72 | \keyword{internal}
73 |
--------------------------------------------------------------------------------
/DESCRIPTION:
--------------------------------------------------------------------------------
1 | Package: cmapplot
2 | Title: CMAP Themes and Color Palettes
3 | Version: 1.2.3
4 | Authors@R: c(
5 | person("Daniel", "Comeaux",
6 | role = c("aut"),
7 | comment = c(ORCID = "0000-0002-8412-9092")),
8 | person("Sarah", "Buchhorn",
9 | role = "aut",
10 | email = ""),
11 | person("Martin", "Menninger",
12 | role = "aut",
13 | email = "mmenninger@cmap.illinois.gov"),
14 | person("Noel", "Peterson",
15 | role = "aut",
16 | comment = c(ORCID = "0000-0003-1290-2362")),
17 | person("Greta", "Ritzenthaler",
18 | role = "aut"),
19 | person("Matthew", "Stern",
20 | role = "aut",
21 | comment = c(ORCID = "0000-0001-9119-2121")),
22 | person("Sean", "Connelly",
23 | role = c("aut", "cre"),
24 | email = "sconnelly@cmap.illinois.gov"),
25 | person("David", "Wells",
26 | role = "aut",
27 | email = "dwells@cmap.illinois.gov"),
28 | person("Chicago Metropolitan Agency for Planning",
29 | role = c("cph", "fnd")))
30 | Description: Provides themes and color scales for 'ggplot2', based on Chicago
31 | Metropolitan Agency for Planning (CMAP) design guidelines.
32 | URL: https://cmap-repos.github.io/cmapplot, https://github.com/CMAP-REPOS/cmapplot
33 | BugReports: https://github.com/CMAP-REPOS/cmapplot/issues
34 | License: MIT + file LICENSE
35 | Encoding: UTF-8
36 | LazyData: true
37 | Depends:
38 | R (>= 3.5.0),
39 | ggplot2
40 | Imports:
41 | dplyr,
42 | generics,
43 | ggpubr,
44 | glue,
45 | graphics,
46 | grDevices,
47 | grid,
48 | gridExtra,
49 | gridtext,
50 | ggrepel,
51 | lubridate,
52 | purrr,
53 | ragg,
54 | Rcpp,
55 | rlang,
56 | rstudioapi,
57 | scales,
58 | stringr,
59 | systemfonts,
60 | tibble,
61 | withr
62 | Suggests:
63 | knitr,
64 | rmarkdown,
65 | testthat (>= 3.0.0),
66 | tidyverse
67 | RoxygenNote: 7.3.3
68 | VignetteBuilder: knitr
69 | Config/testthat/edition: 3
70 |
--------------------------------------------------------------------------------
/NAMESPACE:
--------------------------------------------------------------------------------
1 | # Generated by roxygen2: do not edit by hand
2 |
3 | S3method(makeContent,textlastrepel)
4 | export(.lwd)
5 | export(GeomPandemics)
6 | export(GeomPandemicsText)
7 | export(GeomPointLast)
8 | export(GeomRecessions)
9 | export(GeomRecessionsText)
10 | export(GeomTextLast)
11 | export(GeomTextLastRepel)
12 | export(abbr_years)
13 | export(apply_cmap_default_aes)
14 | export(cmap_color_continuous)
15 | export(cmap_color_discrete)
16 | export(cmap_color_highlight)
17 | export(cmap_color_race)
18 | export(cmap_colour_continuous)
19 | export(cmap_colour_discrete)
20 | export(cmap_colour_highlight)
21 | export(cmap_colour_race)
22 | export(cmap_fill_continuous)
23 | export(cmap_fill_discrete)
24 | export(cmap_fill_highlight)
25 | export(cmap_fill_race)
26 | export(fetch_pal)
27 | export(finalize_plot)
28 | export(geom_pandemics)
29 | export(geom_recessions)
30 | export(geom_text_lastonly)
31 | export(geom_text_lastonly_repel)
32 | export(get_cmapplot_global)
33 | export(get_cmapplot_globals)
34 | export(gg_lwd_convert)
35 | export(position_nudge_repel)
36 | export(set_cmapplot_global)
37 | export(theme_cmap)
38 | export(unapply_cmap_default_aes)
39 | export(update_recessions)
40 | export(viz_gradient)
41 | export(viz_palette)
42 | import(Rcpp)
43 | import(dplyr)
44 | import(ggplot2)
45 | import(ggrepel)
46 | import(grDevices)
47 | import(graphics)
48 | import(grid)
49 | import(gridtext)
50 | import(ragg)
51 | import(rlang)
52 | import(rstudioapi)
53 | import(scales)
54 | import(systemfonts)
55 | importFrom(generics,intersect)
56 | importFrom(ggpubr,get_legend)
57 | importFrom(glue,glue)
58 | importFrom(glue,glue_collapse)
59 | importFrom(gridExtra,arrangeGrob)
60 | importFrom(lubridate,day)
61 | importFrom(lubridate,decimal_date)
62 | importFrom(lubridate,month)
63 | importFrom(lubridate,year)
64 | importFrom(purrr,compact)
65 | importFrom(purrr,map)
66 | importFrom(purrr,walk2)
67 | importFrom(stats,na.omit)
68 | importFrom(stringr,str_length)
69 | importFrom(stringr,str_replace)
70 | importFrom(stringr,str_trunc)
71 | importFrom(tibble,tribble)
72 | importFrom(utils,modifyList)
73 | importFrom(utils,read.csv)
74 |
--------------------------------------------------------------------------------
/man/dot-lwd.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/utilities.R
3 | \docType{data}
4 | \name{.lwd}
5 | \alias{.lwd}
6 | \alias{gg_lwd_convert}
7 | \title{Line width conversion}
8 | \format{
9 | An object of class \code{numeric} of length 1.
10 | }
11 | \usage{
12 | .lwd
13 |
14 | gg_lwd_convert(value, unit = "bigpts")
15 | }
16 | \arguments{
17 | \item{value}{Numeric, the value to be converted.}
18 |
19 | \item{unit}{Char, the unit of the value to be converted. Can be any of the
20 | units accepted by \code{grid::unit()}, including "bigpts", "pt", "mm", and
21 | "in". Default is \code{bigpts}.}
22 | }
23 | \description{
24 | The factor \code{.lwd} is used to calculate correct output sizes for line
25 | widths. For line widths in \code{ggplot2}, the size in mm must be divided
26 | by this factor for correct output. Because the user is likely to prefer
27 | other units besides for mm, \code{gg_lwd_convert()} is provided as a
28 | convenience function, converting from any unit all the way to ggplot units.
29 | }
30 | \details{
31 | \code{.lwd} is equal to \code{ggplot2::.stroke / ggplot2::.pt}. In
32 | \code{ggplot2}, the size in mm is divided by \code{.lwd} to achieve the
33 | correct output. In the \code{grid} package, however, the size in points
34 | (\code{pts} (or maybe \code{bigpts}? Unclear.) must be divided by
35 | \code{.lwd}. The user is unlikely to interact directly with \code{grid},
36 | but this is how \code{finalize_plot()} does its work.
37 |
38 | This is closely related to \code{ggplot::.pt}, which is the factor that
39 | font sizes (in \code{pts}) must be divided by for text geoms within
40 | \code{ggplot2}. Confusingly, \code{.pt} is not required for \code{ggplot2}
41 | font sizes outside the plot area: e.g. axis titles, etc.
42 | }
43 | \section{Functions}{
44 | \itemize{
45 | \item \code{gg_lwd_convert()}: Function to convert from any unit directly to ggplot2's
46 | preferred millimeters.
47 |
48 | }}
49 | \examples{
50 | ggplot() + coord_cartesian(xlim = c(-3, 3), ylim = c(-3, 3)) +
51 |
52 | # a green line 3 points wide
53 | geom_hline(yintercept = 1, color = "green", size = gg_lwd_convert(3)) +
54 |
55 | # black text of size 24 points
56 | annotate("text", -2, 0, label = "text", size = 24/ggplot2::.pt)
57 |
58 |
59 | # a blue line 6 points wide, drawn over the plot with the `grid` package
60 | grid::grid.lines(y = 0.4, gp = grid::gpar(col = "blue", lwd = 6 / .lwd))
61 |
62 | }
63 | \seealso{
64 | grid's \code{\link[grid]{unit}}, ggplot2's
65 | \code{\link[ggplot2]{.pt}}, and
66 | \url{https://stackoverflow.com/questions/17311917/ggplot2-the-unit-of-size}
67 | }
68 | \keyword{datasets}
69 |
--------------------------------------------------------------------------------
/man/abbr_years.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/axis_handling.R
3 | \name{abbr_years}
4 | \alias{abbr_years}
5 | \title{Axis handling helper functions}
6 | \usage{
7 | abbr_years(full_by_pos = c(1), full_by_year = NULL, dateaxis = FALSE)
8 | }
9 | \arguments{
10 | \item{full_by_pos}{Vector of integers, the position of breaks that should not
11 | be abbreviated. This defaults to \code{c(1)}, which retains the original
12 | first label and abbreviates subsequent ones. If all breaks should be
13 | abbreviated, this can be set to NULL.}
14 |
15 | \item{full_by_year}{Vector of integers, the value of breaks that should not be
16 | abbreviated. Defaults to NULL.}
17 |
18 | \item{dateaxis}{Bool. \code{FALSE}, the default, directs the function to treat
19 | the breaks as integers. If set to \code{TRUE} the function will instead
20 | treat the breaks as date objects. \code{TRUE} should be used when called
21 | within a \code{scale_*_date} ggplot element.}
22 | }
23 | \description{
24 | `abbr_years()` is a helper functions that allows users to abbreviate year
25 | labels to their two-digit representation (e.g., 2008 to '08), but not
26 | abbreviate any specified breaks. It does so by creating a new function that
27 | takes the breaks supplied by \code{ggplot2} as its only argument. The
28 | function was modeled after the syntax and approach of the labeling functions
29 | in the \code{scales::label_*} family.
30 | }
31 | \examples{
32 |
33 | # basic functionality
34 | abbr_years()(c(2010:2020))
35 | abbr_years(full_by_year = 2000)(c(1990:2010))
36 |
37 |
38 | # Default implementation - this will abbreviate all labels except the first
39 | # for both continuous and date scales.
40 |
41 | df2 <- dplyr::mutate(transit_ridership, year2 = as.Date(lubridate::date_decimal(year)))
42 | df1 <- dplyr::filter(df2, year >= 2000)
43 |
44 | ggplot(df1,
45 | aes(x = year, y = ridership, color = system)) +
46 | geom_line() +
47 | scale_x_continuous(labels = abbr_years())
48 |
49 | ggplot(df1,
50 | aes(x = year2, y = ridership, color = system)) +
51 | geom_line() +
52 | scale_x_date(labels = abbr_years(dateaxis = TRUE))
53 |
54 | # If customizations are desired, users can use \code{full_by_pos} and/or
55 | # \code{full_by_year} to maintain the full version of the specified labels.
56 |
57 | ggplot(df2,
58 | aes(x = year2, y = ridership, color = system)) +
59 | geom_line() +
60 | scale_x_date(labels = abbr_years(full_by_year = c(2000), dateaxis = TRUE))
61 |
62 | # You can also remove the default maintenance of the first label and only
63 | # specify specific years.
64 | ggplot(df2,
65 | aes(x = year, y = ridership, color = system)) +
66 | geom_line() +
67 | scale_x_continuous(labels = abbr_years(full_by_pos = NULL,
68 | full_by_year = c(1990,2020)))
69 |
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/R/colors_race.R:
--------------------------------------------------------------------------------
1 | #' Race palette prep
2 | #'
3 | #' @param white White/Caucasian
4 | #' @param black Black/African American
5 | #' @param hispanic Hispanic/Latino
6 | #' @param asian Asian
7 | #' @param other Other
8 | #'
9 | #' @noRd
10 | make_race_palette <- function(white, black, hispanic, asian, other) {
11 |
12 | race_palette <- fetch_pal("race")
13 | pal <- c()
14 |
15 | if (missing(white) & missing(black) & missing(hispanic) & missing(asian) & missing(other)) {
16 | pal <- race_palette # if no parameters specified, return default race palette
17 | } else {
18 |
19 | passed <- unlist(as.list(match.call())[-1]) # vector of args actually passed
20 |
21 | for (i in names(race_palette)) {
22 | if (i %in% names(passed)) {
23 | pal[passed[i]] <- race_palette[i]
24 | }
25 | }
26 | }
27 |
28 | return (pal)
29 | }
30 |
31 | #' Apply official CMAP race/ethnicity chart colors to ggplot2 aesthetics
32 | #'
33 | #' Pick the function depending on the aesthetic of your ggplot object (fill or color).
34 | #' Specify your dataset's unique race factor names (as case-sensitive strings) in the arguments.
35 | #' All categories are optional in case your dataset does not have some of them or contains the default
36 | #' values of the race palette.
37 | #'
38 | #' @param white Data value to map CMAP's White/Caucasian color onto (case-sensitive).
39 | #' @param black Data value to map CMAP's Black/African American color onto (case-sensitive).
40 | #' @param hispanic Data value to map CMAP's Hispanic/Latino color onto (case-sensitive).
41 | #' @param asian Data value to map CMAP's Asian color onto (case-sensitive).
42 | #' @param other Data value to map CMAP's Other/Multiple Races color onto (case-sensitive).
43 | #'
44 | #' @examples
45 | #' ggplot(dplyr::filter(traded_emp_by_race, Race!="Regional average" &
46 | #' variable=="SpecializedTraded")) +
47 | #' geom_col(aes(x = Race, y = value, fill = Race)) +
48 | #' cmap_fill_race(white = "White", black = "Black",
49 | #' hispanic = "Hispanic", asian = "Asian",
50 | #' other = "Other")
51 | #'
52 | #' @describeIn cmap_fill_race For fill aesthetic
53 | #' @export
54 | cmap_fill_race <- function(white, black, hispanic, asian, other) {
55 | .args <- as.list(match.call()[-1])
56 | race_palette <- do.call(make_race_palette, .args)
57 | ggplot2::scale_fill_manual(values = race_palette)
58 | }
59 |
60 |
61 | #' @describeIn cmap_fill_race For color aesthetic
62 | #' @export
63 | cmap_color_race <- function(white, black, hispanic, asian, other) {
64 | .args <- as.list(match.call()[-1])
65 | race_palette <- do.call(make_race_palette, .args)
66 | ggplot2::scale_color_manual(values = race_palette)
67 | }
68 |
69 | #' @describeIn cmap_fill_race For color aesthetic
70 | #' @export
71 | cmap_colour_race <- cmap_color_race
72 |
--------------------------------------------------------------------------------
/man/viz_palette.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/colors_continuous.R, R/colors_discrete.R,
3 | % R/utilities.R
4 | \name{viz_gradient}
5 | \alias{viz_gradient}
6 | \alias{viz_palette}
7 | \alias{cmap_palettes}
8 | \alias{cmap_gradients}
9 | \alias{cmap_colors}
10 | \alias{fetch_pal}
11 | \title{Visualizing CMAP color palettes}
12 | \usage{
13 | viz_gradient(pal, ttl = NULL)
14 |
15 | viz_palette(pal, ttl = NULL, num = NULL)
16 |
17 | fetch_pal(
18 | pal,
19 | which = c("discrete", "sequential", "divergent"),
20 | return = c("colors", "type", "exists")
21 | )
22 | }
23 | \arguments{
24 | \item{pal}{character, name of a a cmapplot palette, or a vector of colors
25 | representing a palette}
26 |
27 | \item{ttl}{character, title to be displayed (the name of the palette)}
28 |
29 | \item{num}{numeric, the number of colors to display}
30 |
31 | \item{which}{a vector of palette types to consider}
32 |
33 | \item{return}{Value to return. "colors", the default, returns the palette as
34 | a vector of colors. "type" returns the palette's type. "Exists" returns
35 | TRUE or FALSE based on whether the name is found in the palettes table.}
36 | }
37 | \description{
38 | The cmapplot package contains a many color palettes extracted from the
39 | larger, official CMAP color palette. Helper functions allow the user to
40 | inspect the various palettes before applying them to plots.
41 | }
42 | \details{
43 | Palettes are stored in a tibble the \code{cmapplot_globals} environment. The
44 | user can access this tibble with \code{\link{get_cmapplot_global}}, but it is
45 | easier to access information about a single palette with \code{fetch_pal}.
46 |
47 | \code{viz_palette} and \code{viz_gradient} draw the palette to the plots
48 | window. These functions are modified with respect from the
49 | \href{https://github.com/ropenscilabs/ochRe}{ochRe package}.
50 |
51 | For more information about available cmapplot color palettes and how to apply
52 | them, see \code{vignette("colors")}.
53 | }
54 | \section{Functions}{
55 | \itemize{
56 | \item \code{viz_gradient()}: Interpolates the range of colors a sequential or
57 | divergent palette offers when used on a continuous scale.
58 |
59 | \item \code{viz_palette()}: Displays the colors of any cmapplot palette
60 |
61 | \item \code{fetch_pal()}: Returns details about a palette
62 |
63 | }}
64 | \examples{
65 | # Vizualize a sequential or divergent palette with interpolation
66 | viz_gradient("green_teal_blue")
67 |
68 | # Visualize a single palette as individual colors
69 | viz_palette("legislation")
70 |
71 | # Print names and types of all available palettes
72 | as.data.frame(get_cmapplot_global("palettes")[1:2])
73 |
74 | # Identify the first two colors of the Prosperity Palette
75 | fetch_pal("prosperity")[1:2]
76 |
77 | # Confirm that "reds" is a sequential palette
78 | fetch_pal("reds", which = "sequential", return = "exists")
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/man/cmap_default_aes.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/default_aes.R
3 | \name{cmap_default_aes}
4 | \alias{cmap_default_aes}
5 | \alias{apply_cmap_default_aes}
6 | \alias{unapply_cmap_default_aes}
7 | \title{Fetch and set aesthetic defaults}
8 | \usage{
9 | apply_cmap_default_aes(quietly = FALSE)
10 |
11 | unapply_cmap_default_aes(quietly = FALSE)
12 | }
13 | \arguments{
14 | \item{quietly}{Should the function suppress confirmation message?}
15 | }
16 | \description{
17 | These functions allow for setting and resetting default aesthetic values for
18 | certain ggplot2 geoms. This is necessary for geoms to be "themed" to CMAP
19 | style standards, because (at least at the moment) setting geom aesthetic
20 | defaults on a plot-by-plot basis (such as with \code{ggplot2::theme}) is not
21 | possible. The geoms impacted are stored in
22 | \code{cmapplot_globals$geoms_that_change}.
23 | }
24 | \details{
25 | These functions are employed implicitly within \code{\link{finalize_plot}} to
26 | apply preferred aesthetic defaults to final outputs. They are only necessary
27 | to use explicitly if you would like plots to use these defaults
28 | pre-\code{finalize}.
29 |
30 | CAUTION: Running \code{apply_cmap_default_aes} will set defaults for all
31 | ggplot2 plots drawn in the current session. To reset to \code{ggplot2}
32 | defaults (technically, to whatever the defaults were when \code{cmapplot}
33 | was loaded), use \code{unapply_cmap_default_aes}.
34 |
35 | Note: CMAP aesthetic defaults are loaded into
36 | \code{cmapplot_globals$default_aes_cmap} by the internal pkg function
37 | \code{init_cmap_default_aes} when \code{cmapplot} is first loaded into R.
38 | }
39 | \section{Functions}{
40 | \itemize{
41 | \item \code{apply_cmap_default_aes()}: Apply CMAP aesthetic defaults to all ggplots in
42 | the current session
43 |
44 | \item \code{unapply_cmap_default_aes()}: Reset modified geom aesthetics to their values
45 | when \code{cmapplot} was first loaded
46 |
47 | }}
48 | \examples{
49 | \dontrun{
50 | g <- ggplot(filter(grp_over_time, category == "Services"),
51 | aes(x = year, y = realgrp, color = cluster)) +
52 | geom_recessions(ymax = 0.4, text_nudge_x = 0.1) +
53 | theme_cmap(hline = 0,
54 | axislines = "x",
55 | legend.max.columns = 2) +
56 | ggtitle("Change in gross regional product over time") +
57 | geom_line() +
58 | scale_x_continuous("Year", breaks = seq(2007, 2017, 2)) +
59 | coord_cartesian(clip = "off") +
60 | geom_text_lastonly(aes(label = realgrp), add_points = TRUE)
61 |
62 | # print normally
63 | g
64 |
65 | # overwrite `default_aes`
66 | apply_cmap_default_aes()
67 | g
68 |
69 | # reset `default_aes`
70 | unapply_cmap_default_aes()
71 | g
72 |
73 | # finalize alters the defaults implicitly, but then resets them automatically.
74 | finalize_plot(g)
75 |
76 | # you can also use `finalize` without these modifications
77 | finalize_plot(g, use_cmap_aes = FALSE)
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/R/position_nudge_repel.R:
--------------------------------------------------------------------------------
1 | #' Position Nudge Repel
2 | #'
3 | #' Nudge labels a fixed distance from points
4 | #'
5 | #' \code{position_nudge_repel} is useful for adjusting the starting
6 | #' position of text labels before they are repelled from data points.
7 | #'
8 | #' @family position adjustments
9 | #' @param x,y Amount of horizontal and vertical distance to move. Same units
10 | #' as the data on the x and y axes.
11 | #'
12 | #' @examples
13 | #'
14 | #' library(ggrepel)
15 | #'
16 | #' df <- data.frame(
17 | #' x = c(1,3,2,5),
18 | #' y = c("a","c","d","c")
19 | #' )
20 | #'
21 | #' ggplot(df, aes(x, y)) +
22 | #' geom_point() +
23 | #' geom_text_repel(aes(label = y))
24 | #'
25 | #' ggplot(df, aes(x, y)) +
26 | #' geom_point() +
27 | #' geom_text_repel(
28 | #' aes(label = y),
29 | #' min.segment.length = 0,
30 | #' position = position_nudge_repel(x = 0.1, y = 0.15)
31 | #' )
32 | #'
33 | #' # The values for x and y can be vectors
34 | #' ggplot(df, aes(x, y)) +
35 | #' geom_point() +
36 | #' geom_text_repel(
37 | #' aes(label = y),
38 | #' min.segment.length = 0,
39 | #' position = position_nudge_repel(
40 | #' x = c(0.1, 0, -0.1, 0),
41 | #' y = c(0.1, 0.2, -0.1, -0.2)
42 | #' )
43 | #' )
44 | #'
45 | #' # We can also use geom_text_repel() with arguments nudge_x, nudge_y
46 | #' ggplot(df, aes(x, y)) +
47 | #' geom_point() +
48 | #' geom_text_repel(
49 | #' aes(label = y),
50 | #' min.segment.length = 0,
51 | #' nudge_x = 0.1,
52 | #' nudge_y = 0.15
53 | #' )
54 | #'
55 | #' # The arguments nudge_x, nudge_y also accept vectors
56 | #' ggplot(df, aes(x, y)) +
57 | #' geom_point() +
58 | #' geom_text_repel(
59 | #' aes(label = y),
60 | #' min.segment.length = 0,
61 | #' nudge_x = c(0.1, 0, -0.1, 0),
62 | #' nudge_y = c(0.1, 0.2, -0.1, -0.2)
63 | #' )
64 | #'
65 | #' @format NULL
66 | #' @usage NULL
67 | #' @keywords internal
68 | #' @export
69 | position_nudge_repel <- function(x = 0, y = 0) {
70 | ggproto(NULL, PositionNudgeRepel, x = x, y = y)
71 | }
72 |
73 | PositionNudgeRepel <- ggproto(
74 | "PositionNudgeRepel",
75 | Position,
76 | x = 0,
77 | y = 0,
78 |
79 | setup_params = function(self, data) {
80 | list(x = self$x, y = self$y)
81 | },
82 |
83 | compute_layer = function(self, data, params, layout) {
84 | x_orig <- data$x
85 | y_orig <- data$y
86 | # transform only the dimensions for which non-zero nudging is requested
87 | if (any(params$x != 0)) {
88 | if (any(params$y != 0)) {
89 | data <- transform_position(data, function(x) x + params$x, function(y) {
90 | y + params$y
91 | })
92 | } else {
93 | data <- transform_position(data, function(x) x + params$x, NULL)
94 | }
95 | } else if (any(params$y != 0)) {
96 | data <- transform_position(data, NULL, function(y) y + params$y)
97 | }
98 | data$x_orig <- x_orig
99 | data$y_orig <- y_orig
100 | data
101 | }
102 | )
103 |
--------------------------------------------------------------------------------
/man/cmap_fill_highlight.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/colors_highlight.R
3 | \name{cmap_fill_highlight}
4 | \alias{cmap_fill_highlight}
5 | \alias{cmap_color_highlight}
6 | \alias{cmap_colour_highlight}
7 | \title{Highlight one or more discrete groups in a comparison graph}
8 | \usage{
9 | cmap_fill_highlight(
10 | field,
11 | value,
12 | color_value = "#008FD5",
13 | color_other = "#b0bdcf"
14 | )
15 |
16 | cmap_color_highlight(
17 | field,
18 | value,
19 | color_value = "#008FD5",
20 | color_other = "#b0bdcf"
21 | )
22 |
23 | cmap_colour_highlight(
24 | field,
25 | value,
26 | color_value = "#008FD5",
27 | color_other = "#b0bdcf"
28 | )
29 | }
30 | \arguments{
31 | \item{field}{character vector, the vector in which the value to highlight is
32 | found. Values need not be unique. Typically, pass the table column that
33 | defines the color/fill aesthetic as 'table$field'}
34 |
35 | \item{value}{character string or vector, the name of group(s) to highlight}
36 |
37 | \item{color_value}{Specify the highlight color(s). Default is #00b0f0 (blue)}
38 |
39 | \item{color_other}{Specify non-highlighted color. Default is #b0bdcf (gray)}
40 | }
41 | \description{
42 | Pick the function depending on the aesthetic of your ggplot object (fill or
43 | color). Specify the unique factor name(s) of the group(s) you're highlighting
44 | (as a case-sensitive string), and the vector it's found in.
45 | }
46 | \details{
47 | You may specify multiple groups to highlight. If you do, you may specify a
48 | single highlight color, or a vector of highlight colors of equal length to
49 | the vector of highlight values.
50 |
51 | This function does not make any modifications to the legend, so legend
52 | behavior is not perfect out-of-the-box. For example, if the plot aesthetic
53 | differentiates between five unique values, all five values will appear in the
54 | legend, even though four use the same color. You will likely want to hide the
55 | legend altogether, or manufacture a new data field that contains only the
56 | value(s) to highlight and some generic "Other" label.
57 | }
58 | \section{Functions}{
59 | \itemize{
60 | \item \code{cmap_fill_highlight()}: For fill aesthetic
61 |
62 | \item \code{cmap_color_highlight()}: For color aesthetic
63 |
64 | \item \code{cmap_colour_highlight()}: For color aesthetic, if you're British
65 |
66 | }}
67 | \examples{
68 | p <- ggplot(data = dplyr::filter(transit_ridership, year=="2019"),
69 | mapping = aes(x = system, y = ridership, fill = system)) +
70 | geom_col()
71 |
72 | # one value, default colors
73 | p + cmap_fill_highlight(field = transit_ridership$system,
74 | value = "metra")
75 |
76 | # multiple values, default colors
77 | p + cmap_fill_highlight(field = transit_ridership$system,
78 | value = c("metra", "pace_ada"))
79 |
80 | # multiple values, multiple colors
81 | p + cmap_fill_highlight(
82 | field = transit_ridership$system,
83 | value = c("metra", "pace_ada"),
84 | color_value = c("red", "orange")
85 | )
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/vignettes/installation.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Installing cmapplot on a CMAP computer"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{Installing cmapplot on a CMAP computer}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | This vignette provides an overview of how to install cmapplot, with a specific focus on CMAP-issued computers. This guide presumes that the user does *not* have administrator privileges.
11 |
12 |
13 | ## Prerequisites
14 |
15 | Your CMAP computer should already have both R and RStudio installed. If it does not, please submit an IT helpdesk request to install them. (While you can install RStudio on your own by [downloading](https://rstudio.com/products/rstudio/download/#download) the .zip -- *not* .exe -- version, installing R itself requires administrator privileges).
16 |
17 | Once you have working versions of R and RStudio on your computer, you will also need to download an additional utility called Rtools. You can download the installation file for Rtools [here](https://cran.rstudio.com/bin/windows/Rtools/). Because of IT restrictions, you will need to choose an installation folder that you have write access to. The Rtools installer defaults to **C:\\rtools40**, which is fine. However, if you do not want to install it there, you may create another folder in your own user sub-directory (e.g. **C:\\Users\\your_username\\rtools**).
18 |
19 | Finally, before you can install cmapplot, you will need to download and install the "devtools" and "tidyverse" packages. You can install them by running the following code in RStudio:
20 |
21 | ```{r install-devtools, eval=FALSE}
22 | ## Install devtools & tidyverse
23 | install.packages(c("devtools", "tidyverse"))
24 | ```
25 |
26 |
27 | ## Installing and loading cmapplot
28 |
29 | Once you have successfully downloaded and installed Rtools and the "devtools" and "tidyverse" packages, you are ready to install cmapplot. Run the following code to install and load cmapplot:
30 |
31 | ```{r install-cmapplot, eval=FALSE}
32 | ## Install/update cmapplot from GitHub
33 | devtools::install_github("CMAP-REPOS/cmapplot", build_vignettes=TRUE)
34 |
35 | ## Load cmapplot
36 | library(cmapplot)
37 | ```
38 |
39 | After completing these steps, your computer should be ready to use and export graphics using cmapplot.
40 |
41 |
42 | ## CMAP fonts
43 |
44 | CMAP's design standards require the usage of the Whitney typeface. Whitney is not freely available, but rather requires a license. On CMAP computers, which should already have the Whitney font family installed, cmapplot will use Whitney without any issues. If you receive a warning that Whitney is not installed when you load the package, please verify that the Whitney fonts (specifically, the Book, Medium and Semibold variants) are installed. If they are not, please submit an IT helpdesk request to get them installed. If the Whitney font family *is* already installed and you are receiving the warning message, please reach out to a member of the cmapplot development team.
45 |
46 | Non-CMAP users will have to license Whitney on their own, or else use cmapplot without. The package will default to your system's default sans-serif font, which is likely Arial.
47 |
--------------------------------------------------------------------------------
/.github/workflows/check-standard.yaml:
--------------------------------------------------------------------------------
1 | # Automatically checks the package on Windows and Mac each time master branch
2 | # (or a pull request to master) gets a new commit.
3 | # Based on .
4 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag.
5 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions
6 | on:
7 | push:
8 | branches:
9 | - main
10 | - master
11 | pull_request:
12 | branches:
13 | - main
14 | - master
15 |
16 | name: R-CMD-check
17 |
18 | jobs:
19 | R-CMD-check:
20 | runs-on: ${{ matrix.config.os }}
21 |
22 | name: ${{ matrix.config.os }} (${{ matrix.config.r }})
23 |
24 | strategy:
25 | fail-fast: false
26 | matrix:
27 | config:
28 | - {os: windows-latest, r: 'release'}
29 | - {os: macOS-latest, r: 'release'}
30 | #- {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
31 | #- {os: ubuntu-20.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"}
32 |
33 | env:
34 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true
35 | RSPM: ${{ matrix.config.rspm }}
36 |
37 | steps:
38 | - uses: actions/checkout@v3
39 |
40 | - uses: r-lib/actions/setup-r@v2
41 | with:
42 | r-version: ${{ matrix.config.r }}
43 |
44 | - uses: r-lib/actions/setup-pandoc@v2
45 |
46 | - name: Query dependencies
47 | run: |
48 | install.packages('remotes')
49 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
50 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
51 | shell: Rscript {0}
52 |
53 | - name: Cache R packages
54 | if: runner.os != 'Windows'
55 | uses: actions/cache@v3
56 | with:
57 | path: ${{ env.R_LIBS_USER }}
58 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
59 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
60 |
61 | #- name: Install system dependencies
62 | # if: runner.os == 'Linux'
63 | # run: |
64 | # while read -r cmd
65 | # do
66 | # eval sudo $cmd
67 | # done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))')
68 |
69 | - name: Install XQuartz on macOS
70 | if: runner.os == 'macOS'
71 | run: |
72 | brew install --cask xquartz
73 |
74 | - name: Install dependencies
75 | run: |
76 | remotes::install_deps(dependencies = TRUE)
77 | remotes::install_cran("rcmdcheck")
78 | shell: Rscript {0}
79 |
80 | - name: Check
81 | env:
82 | _R_CHECK_CRAN_INCOMING_REMOTE_: false
83 | run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "error", check_dir = "check")
84 | shell: Rscript {0}
85 |
86 | - name: Upload check results
87 | if: failure()
88 | uses: actions/upload-artifact@main
89 | with:
90 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results
91 | path: check
92 |
--------------------------------------------------------------------------------
/.github/workflows/pkgdown.yaml:
--------------------------------------------------------------------------------
1 | # Automatically rebuilds pkgdown website any time master branch is updated.
2 | # Also builds pkgdown on "gh-pages-test" on commits to pull requests.
3 | # Based on .
4 | # Conditional based on .
5 | on:
6 | push:
7 | branches: master
8 | pull_request:
9 |
10 | name: pkgdown
11 |
12 | jobs:
13 | pkgdown:
14 | runs-on: macOS-latest
15 | env:
16 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
17 | steps:
18 | - uses: actions/checkout@v3
19 |
20 | - uses: r-lib/actions/setup-r@v2
21 |
22 | - uses: r-lib/actions/setup-pandoc@v2
23 |
24 | - name: Checkout CMAP fonts repo
25 | uses: actions/checkout@v3
26 | with:
27 | repository: CMAP-REPOS/cmap-fonts
28 | token: ${{ secrets.CMAP_REPO_FULL_ACCESS }}
29 | path: cmap-fonts
30 |
31 | - name: Install CMAP fonts for R access
32 | # Inspiration: https://gist.github.com/Kevin-Lee/328e9993d6b3ad250636023fb2c7827f
33 | run: |
34 | repo_dir="$GITHUB_WORKSPACE/cmap-fonts"
35 | font_dir="$HOME/Library/Fonts"
36 | mkdir -p $font_dir
37 | find_command="find \"$repo_dir\" -name '*.[o,t]tf' -type f -print0"
38 | eval $find_command | xargs -0 -I %
39 | eval $find_command | xargs -0 -I % cp "%" "$font_dir/"
40 | find "$font_dir" -name '*.[o,t]tf' -print0 | xargs -0 -I %
41 |
42 | - name: Query dependencies
43 | run: |
44 | install.packages('remotes')
45 | saveRDS(remotes::dev_package_deps(dependencies = TRUE), ".github/depends.Rds", version = 2)
46 | writeLines(sprintf("R-%i.%i", getRversion()$major, getRversion()$minor), ".github/R-version")
47 | shell: Rscript {0}
48 |
49 | - name: Cache R packages
50 | uses: actions/cache@v3
51 | with:
52 | path: ${{ env.R_LIBS_USER }}
53 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }}
54 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-
55 |
56 | - name: Install dependencies
57 | run: |
58 | remotes::install_deps(dependencies = TRUE)
59 | install.packages("pkgdown")
60 | shell: Rscript {0}
61 |
62 | - name: Check Whitney availability in R
63 | run: |
64 | all_fonts <- systemfonts::system_fonts()
65 | message("WHITNEY FONTS AUTOMATICALLY AVAILABLE TO SYSTEMFONTS:")
66 | message(paste(all_fonts$name[grepl("^Whitney", all_fonts$name)], collapse = "\n"))
67 | user_dir <- paste0(Sys.getenv("HOME"), "/Library/Fonts")
68 | library_fonts <- list.files(user_dir)
69 | message(paste0("WHITNEY FONTS IN ", user_dir, " (MUST BE REGISTERED):"))
70 | message(paste(library_fonts[grepl("^Whitney", library_fonts)], collapse = "\n"))
71 | shell: Rscript {0}
72 |
73 | - name: Install package
74 | run: R CMD INSTALL .
75 |
76 | - name: Deploy package to live branch
77 | if: ${{ github.ref == 'refs/heads/master' }}
78 | run: |
79 | echo "This is $GITHUB_REF. Deploying to gh-pages branch."
80 | git config --local user.email "actions@github.com"
81 | git config --local user.name "GitHub Actions"
82 | Rscript -e 'pkgdown::deploy_to_branch(clean = TRUE)'
83 |
84 | - name: Deploy package to test branch
85 | if: ${{ github.ref != 'refs/heads/master' }}
86 | run: |
87 | echo "This is $GITHUB_REF. Deploying to gh-pages-test branch."
88 | git config --local user.email "actions@github.com"
89 | git config --local user.name "GitHub Actions"
90 | Rscript -e 'pkgdown::deploy_to_branch(branch="gh-pages-test", clean = TRUE)'
91 |
--------------------------------------------------------------------------------
/R/colors_highlight.R:
--------------------------------------------------------------------------------
1 | #' Highlight one or more discrete groups in a comparison graph
2 | #'
3 | #' Pick the function depending on the aesthetic of your ggplot object (fill or
4 | #' color). Specify the unique factor name(s) of the group(s) you're highlighting
5 | #' (as a case-sensitive string), and the vector it's found in.
6 | #'
7 | #' You may specify multiple groups to highlight. If you do, you may specify a
8 | #' single highlight color, or a vector of highlight colors of equal length to
9 | #' the vector of highlight values.
10 | #'
11 | #' This function does not make any modifications to the legend, so legend
12 | #' behavior is not perfect out-of-the-box. For example, if the plot aesthetic
13 | #' differentiates between five unique values, all five values will appear in the
14 | #' legend, even though four use the same color. You will likely want to hide the
15 | #' legend altogether, or manufacture a new data field that contains only the
16 | #' value(s) to highlight and some generic "Other" label.
17 | #'
18 | #' @param field character vector, the vector in which the value to highlight is
19 | #' found. Values need not be unique. Typically, pass the table column that
20 | #' defines the color/fill aesthetic as 'table$field'
21 | #' @param value character string or vector, the name of group(s) to highlight
22 | #' @param color_value Specify the highlight color(s). Default is #00b0f0 (blue)
23 | #' @param color_other Specify non-highlighted color. Default is #b0bdcf (gray)
24 | #'
25 | #' @examples
26 | #' p <- ggplot(data = dplyr::filter(transit_ridership, year=="2019"),
27 | #' mapping = aes(x = system, y = ridership, fill = system)) +
28 | #' geom_col()
29 | #'
30 | #' # one value, default colors
31 | #' p + cmap_fill_highlight(field = transit_ridership$system,
32 | #' value = "metra")
33 | #'
34 | #' # multiple values, default colors
35 | #' p + cmap_fill_highlight(field = transit_ridership$system,
36 | #' value = c("metra", "pace_ada"))
37 | #'
38 | #' # multiple values, multiple colors
39 | #' p + cmap_fill_highlight(
40 | #' field = transit_ridership$system,
41 | #' value = c("metra", "pace_ada"),
42 | #' color_value = c("red", "orange")
43 | #' )
44 | #'
45 | #' @describeIn cmap_fill_highlight For fill aesthetic
46 | #' @export
47 | cmap_fill_highlight <- function(field,
48 | value,
49 | color_value = "#008FD5",
50 | color_other = "#b0bdcf") {
51 |
52 | palette <- make_highlight_palette(field, value, color_value, color_other)
53 |
54 | ggplot2::scale_fill_manual(values = palette)
55 |
56 | }
57 |
58 | #' @describeIn cmap_fill_highlight For color aesthetic
59 | #' @export
60 | cmap_color_highlight <- function(field,
61 | value,
62 | color_value = "#008FD5",
63 | color_other = "#b0bdcf") {
64 |
65 | palette <- make_highlight_palette(field, value, color_value, color_other)
66 |
67 | ggplot2::scale_color_manual(values = palette)
68 |
69 | }
70 |
71 | #' @describeIn cmap_fill_highlight For color aesthetic, if you're British
72 | #' @export
73 | cmap_colour_highlight <- cmap_color_highlight
74 |
75 |
76 |
77 | #' Highlight palette prep function
78 | #'
79 | #' Create named list to serve as palette input for following fill/color highlight functions
80 | #'
81 | #' @param field group vector
82 | #' @param value name of group of interest
83 | #' @param color_value hexcode of highlighted color
84 | #' @param color_other hexcode of non-highlighted color
85 | #'
86 | #' @noRd
87 | make_highlight_palette <- function(field, value, color_value, color_other) {
88 |
89 | # check that value and color_value are the same length.
90 | # if color_value has a length of 1, it will be repeated
91 | if (length(value) > 1) {
92 | if (length(color_value) == 1) {
93 | color_value <- rep.int(color_value, length(value))
94 | } else if (length(value) != length(color_value)) {
95 | stop("Length of `value` and `color_value` must be equal.", .call = FALSE)
96 | }
97 | }
98 |
99 | # identify palette length
100 | n <- length(unique(field))
101 |
102 | # construct initial palette
103 | palette <- rep.int(c(other = color_other), n)
104 | names(palette) <- levels(factor(field))
105 |
106 | # replace highlight value(s) with highlight color(s)
107 | for (i in seq_along(value)) {
108 | palette[[value[i]]] <- color_value[i]
109 | }
110 |
111 | return(palette)
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/R/colors_continuous.R:
--------------------------------------------------------------------------------
1 | #' Visualizing CMAP color palettes
2 | #'
3 | #' @describeIn viz_palette Interpolates the range of colors a sequential or
4 | #' divergent palette offers when used on a continuous scale.
5 | #'
6 | #' @examples
7 | #' # Vizualize a sequential or divergent palette with interpolation
8 | #' viz_gradient("green_teal_blue")
9 | #'
10 | #' @export
11 | viz_gradient <- function(pal, ttl = NULL) {
12 |
13 | # if `pal` is a named sequential or divergent CMAP palette...
14 | if (fetch_pal(pal[1], c("sequential", "divergent"), "exists")) {
15 | # use the palette as the title (unless a custom title has been provided)
16 | if (is.null(ttl) | missing(ttl)){ ttl <- pal }
17 | # and extract the palette colors
18 | pal <- fetch_pal(pal)
19 | } else {
20 | # otherwise, use the object name as the title (unless a custom title has been provided)
21 | if (is.null(ttl) | missing(ttl)){ ttl <- deparse(substitute(pal)) }
22 | }
23 |
24 | pal_func <- grDevices::colorRampPalette(pal, space = "Lab")
25 | graphics::image(seq_len(300), 1, as.matrix(seq_len(300)), col = pal_func(300),
26 | main = ttl, xlab = "", ylab = "",
27 | xaxt = "n", yaxt = "n", bty = "n")
28 | }
29 |
30 |
31 | #' Continuous palette prep function
32 | #'
33 | #' @param palette A CMAP palette name
34 | #' @param reverse Logical; reverse color order?
35 | #'
36 | #' @noRd
37 | cmap_pal_continuous <- function(palette = "blues", reverse = FALSE) {
38 | pal <- fetch_pal(palette)
39 | if (reverse) { pal <- rev(pal) }
40 | return(grDevices::colorRampPalette(pal))
41 | }
42 |
43 |
44 | #' Internal helper function to rescale. Credit for idea is due to ijlyttle:
45 | # \url{https://github.com/tidyverse/ggplot2/issues/3738#issuecomment-583750802}
46 | #'
47 | #' @noRd
48 | mid_rescaler2 <- function(mid) {
49 | function(x, to = c(0, 1), from = range(x, na.rm = TRUE)) {
50 | scales::rescale_mid(x, to, from, mid)
51 | }
52 | }
53 |
54 |
55 | #' Apply continuous CMAP palettes (gradients) to ggplot2 aesthetics
56 | #'
57 | #' Pick the function depending on the aesthetic of your ggplot object (fill or
58 | #' color). On diverging palettes, a midpoint can be manually adjusted (defaults
59 | #' to 0). See \code{\link{cmap_gradients}} for a listing of available gradients.
60 | #'
61 | #' @param palette String; Choose from 'cmap_gradients' list
62 | #' @param reverse Logical; Reverse color order?
63 | #' @param middle Numeric; Sets midpoint for diverging color palettes. Default =
64 | #' 0.
65 | #' @param ... Additional parameters passed on to the scale type
66 | #'
67 | #' @examples
68 | #' ggplot(dplyr::filter(grp_over_time, cluster=="Biopharmaceuticals"),
69 | #' aes(x = year, y = realgrp, color = realgrp)) +
70 | #' geom_line() +
71 | #' cmap_color_continuous(palette = "red_purple")
72 | #'
73 | #' @describeIn cmap_fill_continuous for fill aesthetic
74 | #'
75 | #' @export
76 | cmap_fill_continuous <- function(palette = "blues",
77 | reverse = FALSE,
78 | middle = 0,
79 | ...) {
80 | type <- fetch_pal(palette, return = "type")
81 |
82 | if (type == "divergent") {
83 | ggplot2::scale_fill_gradientn(
84 | colours = cmap_pal_continuous(palette, reverse = reverse)(256),
85 | rescaler = mid_rescaler2(middle),
86 | ...
87 | )
88 | } else if (type == "sequential"){
89 | ggplot2::scale_fill_gradientn(
90 | colours = cmap_pal_continuous(palette, reverse = reverse)(256),
91 | ...
92 | )
93 | } else {
94 | NULL
95 | }
96 | }
97 |
98 |
99 | #' @describeIn cmap_fill_continuous for color aesthetic
100 | #'
101 | #' @export
102 | cmap_color_continuous <- function(palette = "blues",
103 | reverse = FALSE,
104 | middle = 0,
105 | ...) {
106 | type <- fetch_pal(palette, return = "type")
107 |
108 | if (type == "divergent") {
109 | ggplot2::scale_colour_gradientn(
110 | colours = cmap_pal_continuous(palette, reverse = reverse)(256),
111 | rescaler = mid_rescaler2(middle),
112 | ...
113 | )
114 | } else if (type == "sequential"){
115 | ggplot2::scale_colour_gradientn(
116 | colours = cmap_pal_continuous(palette, reverse = reverse)(256),
117 | ...
118 | )
119 | } else {
120 | NULL
121 | }
122 | }
123 |
124 | #' @describeIn cmap_fill_continuous for color aesthetic
125 | #' @export
126 | cmap_colour_continuous <- cmap_color_continuous
127 |
--------------------------------------------------------------------------------
/man/get_cmapplot_globals.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/cmapplot_globals.R
3 | \name{get_cmapplot_globals}
4 | \alias{get_cmapplot_globals}
5 | \alias{cmapplot_globals}
6 | \alias{get_cmapplot_global}
7 | \alias{set_cmapplot_global}
8 | \title{The cmapplot_globals environment}
9 | \usage{
10 | get_cmapplot_globals()
11 |
12 | get_cmapplot_global(...)
13 |
14 | set_cmapplot_global(value, ..., quietly = FALSE)
15 | }
16 | \arguments{
17 | \item{...}{The path to the variable within \code{cmapplot_globals} to be
18 | get/set. The function willparse \code{$}, or recursive list elements can be
19 | split over multiple arguments (e.g. \code{"font$strong$family"} is
20 | equivalent to \code{"font", "strong", "family"}).}
21 |
22 | \item{value}{the value to be set}
23 |
24 | \item{quietly}{suppress confirmatory messages}
25 | }
26 | \description{
27 | The \code{cmapplot_globals} environment contains a list of predefined
28 | variables for use by the cmapplot package and its users. It includes commonly
29 | used colors, font and font size specifications, and a list of constants which
30 | aid in drawing cmap-themed plots. It cannot be accessed directly, but the
31 | helper functions described here provide the user access if needed.
32 | }
33 | \section{Functions}{
34 | \itemize{
35 | \item \code{get_cmapplot_globals()}: Get the entire environment as a list.
36 |
37 | \item \code{get_cmapplot_global()}: Get a specific global value
38 |
39 | \item \code{set_cmapplot_global()}: Set a specific global value
40 |
41 | }}
42 | \section{Plot Constants}{
43 | The primary portion of these global variables of
44 | interest to the user is \code{cmapplot_globals$consts}, a list of default
45 | constants that set certain plot aesthetics. Units of all plot constants are
46 | "bigpts": 1/72 of an inch. Most plot constants are invoked (and can be
47 | overridden) in \code{\link{finalize_plot}}: these are marked below with an
48 | \strong{F}. Some are used/can be overridden in \code{\link{theme_cmap}}:
49 | these are marked with \strong{T}.
50 |
51 | \itemize{ \item \code{lwd_strongline}: This stronger-width line is drawn
52 | vertically or horizontally with the \code{hline, vline} args of
53 | \code{theme_cmap()}. \strong{(T)} \item \code{lwd_gridline}: This
54 | thinner-width line is drawn vertically or horizontally with the
55 | \code{gridlines, axislines} args of \code{theme_cmap()}. \strong{(T)} \item
56 | \code{lwd_plotline}: The width of any lines drawn by geoms in the plot (e.g.
57 | \code{geom_line}) but not explicitly sized by the geom's aesthetic.
58 | Implemented by \code{finalize_plot} or by \code{apply_cmap_default_aes} but
59 | not overridable in either context. (Modify by setting the size explicitly in
60 | the geom, but see \code{gg_lwd_convert} first.) \item \code{lwd_topline}:
61 | The width of the line above the plot. \strong{(F)} \item
62 | \code{length_ticks}: The length of the axis ticks (if shown). \strong{(T)}
63 | \item \code{margin_topline_t}: The margin between the top edge of the image
64 | and the top line. \strong{(F)} \item \code{margin_title_t}: The margin
65 | between the top line and the title. \strong{(F)} \item
66 | \code{margin_title_b}: The margin between the title and the caption when
67 | both are drawn in the sidebar. \strong{(F)} \item \code{margin_caption_b}:
68 | The margin between the bottom of the caption and the bottom edge of the
69 | image. \strong{(F)} \item \code{margin_legend_t}: The margin between the top
70 | line and the plot box (i.e., the top of the legend). \strong{(F)} \item
71 | \code{margin_legend_i}: The margin between legends (this only applies in
72 | plots with two or more legends and does not affect legend spacing on plots
73 | with single legends that have multiple rows). \strong{(T, F)} \item
74 | \code{margin_legend_b}: The margin between the bottom of the legend and the
75 | rest of the plot. \strong{(T, F)} \item \code{margin_plot_b}: The margin
76 | between the bottom of the plot and the bottom edge of the image (or top of
77 | caption). \strong{(F)} \item \code{margin_sidebar_l}: The margin between the
78 | left edge of the image and the title and caption, when the sidebar exists.
79 | Deducted from \code{title_width}. \strong{(F)} \item \code{margin_plot_l}:
80 | The margin between the left edge of the plot and the sodebar. \strong{(F)}
81 | \item \code{margin_plot_r}: The margin between the right edge of the plot
82 | and the edge of the image. \strong{(F)} \item \code{margin_panel_r}: Padding
83 | between the plot and its right-hand drawing extent. Override this based on
84 | space needed for x axis labels. \strong{(T)} \item \code{leading_title}:
85 | Text leading for Title text. \strong{(F)} \item \code{leading_caption}: Text
86 | leading for Caption text. \strong{(F)} }
87 | }
88 |
89 | \examples{
90 |
91 | # These are the same:
92 | get_cmapplot_global("consts$lwd_gridline")
93 | get_cmapplot_global("consts", "lwd_gridline")
94 |
95 |
96 | # Globals can be modified if needed
97 | set_cmapplot_global(5, "consts$lwd_gridline")
98 | get_cmapplot_global("consts$lwd_gridline")
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/R/axis_handling.R:
--------------------------------------------------------------------------------
1 | #'Axis handling helper functions
2 | #'
3 | #'`abbr_years()` is a helper functions that allows users to abbreviate year
4 | #'labels to their two-digit representation (e.g., 2008 to '08), but not
5 | #'abbreviate any specified breaks. It does so by creating a new function that
6 | #'takes the breaks supplied by \code{ggplot2} as its only argument. The
7 | #'function was modeled after the syntax and approach of the labeling functions
8 | #'in the \code{scales::label_*} family.
9 | #'
10 | #'@importFrom stringr str_length
11 | #'@importFrom lubridate year month day
12 | #'@importFrom stats na.omit
13 | #'
14 | #'@examples
15 | #'
16 | #'# basic functionality
17 | #'abbr_years()(c(2010:2020))
18 | #'abbr_years(full_by_year = 2000)(c(1990:2010))
19 | #'
20 | #'
21 | #' # Default implementation - this will abbreviate all labels except the first
22 | #' # for both continuous and date scales.
23 | #'
24 | #' df2 <- dplyr::mutate(transit_ridership, year2 = as.Date(lubridate::date_decimal(year)))
25 | #' df1 <- dplyr::filter(df2, year >= 2000)
26 | #'
27 | #' ggplot(df1,
28 | #' aes(x = year, y = ridership, color = system)) +
29 | #' geom_line() +
30 | #' scale_x_continuous(labels = abbr_years())
31 | #'
32 | #' ggplot(df1,
33 | #' aes(x = year2, y = ridership, color = system)) +
34 | #' geom_line() +
35 | #' scale_x_date(labels = abbr_years(dateaxis = TRUE))
36 | #'
37 | #' # If customizations are desired, users can use \code{full_by_pos} and/or
38 | #' # \code{full_by_year} to maintain the full version of the specified labels.
39 | #'
40 | #' ggplot(df2,
41 | #' aes(x = year2, y = ridership, color = system)) +
42 | #' geom_line() +
43 | #' scale_x_date(labels = abbr_years(full_by_year = c(2000), dateaxis = TRUE))
44 | #'
45 | #' # You can also remove the default maintenance of the first label and only
46 | #' # specify specific years.
47 | #' ggplot(df2,
48 | #' aes(x = year, y = ridership, color = system)) +
49 | #' geom_line() +
50 | #' scale_x_continuous(labels = abbr_years(full_by_pos = NULL,
51 | #' full_by_year = c(1990,2020)))
52 | #'
53 | #'
54 | #'@param full_by_pos Vector of integers, the position of breaks that should not
55 | #' be abbreviated. This defaults to \code{c(1)}, which retains the original
56 | #' first label and abbreviates subsequent ones. If all breaks should be
57 | #' abbreviated, this can be set to NULL.
58 | #'@param full_by_year Vector of integers, the value of breaks that should not be
59 | #' abbreviated. Defaults to NULL.
60 | #'@param dateaxis Bool. \code{FALSE}, the default, directs the function to treat
61 | #' the breaks as integers. If set to \code{TRUE} the function will instead
62 | #' treat the breaks as date objects. \code{TRUE} should be used when called
63 | #' within a \code{scale_*_date} ggplot element.
64 | #'
65 | #'@export
66 | abbr_years <- function(full_by_pos = c(1),
67 | full_by_year = NULL,
68 | dateaxis = FALSE) {
69 |
70 | fxn <- function(breaks) {
71 |
72 | # If a date axis, breaks are stored by ggplot as the number of days since
73 | # the origin date of January 1, 1970. These must be converted to integer
74 | # years, but this should error if all breaks don't fall on the same calendar
75 | # day of a distinct year.
76 | if (dateaxis) {
77 | dates <- as.Date(breaks, origin = "1970-01-01")
78 |
79 | if (length(unique(month(stats::na.omit(dates)))) != 1 |
80 | length(unique(day(stats::na.omit(dates)))) != 1) {
81 | message(paste(
82 | paste("Currently, breaks are:", paste(dates[!is.na(dates)], collapse = ", ")),
83 | "This function only works if all breaks are on identical calendar days.",
84 | sep = "\n")
85 | )
86 | stop("Breaks cannot be abbreviated.", call. = FALSE)
87 | }
88 |
89 | breaks <- lubridate::year(dates)
90 | }
91 |
92 | # Stop if the breaks are not in a four-digit format.
93 | if (!all(stringr::str_length(breaks) == 4, na.rm = TRUE)) {
94 | message(paste(
95 | paste("Currently, breaks are:", paste(breaks[!is.na(breaks)], collapse = ", ")),
96 | "Remove any breaks that contain decimals. Consider `breaks = scales::pretty_breaks()`",
97 | "If the axis is in date format, use `abbr_years(dateaxis = TRUE)`.",
98 | sep = "\n")
99 | )
100 | stop("Breaks cannot be abbreviated.", call. = FALSE)
101 | }
102 |
103 | # Abbreviate all values
104 | abbr <- paste0("'",substr(breaks,3,4))
105 |
106 | # If there is a leading NA, increment up positions accordingly
107 | leading_na <- which.min(is.na(breaks)) - 1
108 | if(!is.null(full_by_pos)) {
109 | full_by_pos <- full_by_pos + leading_na
110 | }
111 |
112 | # Convert specified years into positions
113 | if(!is.null(full_by_year)) {
114 | full_by_pos <- sort(unique(c(full_by_pos,match(full_by_year,breaks))))
115 | }
116 |
117 | # Add back full years for specified positions
118 | abbr[full_by_pos] <- breaks[full_by_pos]
119 |
120 | return(abbr)
121 | }
122 |
123 | return(fxn)
124 | }
125 |
--------------------------------------------------------------------------------
/R/colors_discrete.R:
--------------------------------------------------------------------------------
1 | #' Visualizing CMAP color palettes
2 | #'
3 | #' The cmapplot package contains a many color palettes extracted from the
4 | #' larger, official CMAP color palette. Helper functions allow the user to
5 | #' inspect the various palettes before applying them to plots.
6 | #'
7 | #' Palettes are stored in a tibble the \code{cmapplot_globals} environment. The
8 | #' user can access this tibble with \code{\link{get_cmapplot_global}}, but it is
9 | #' easier to access information about a single palette with \code{fetch_pal}.
10 | #'
11 | #' \code{viz_palette} and \code{viz_gradient} draw the palette to the plots
12 | #' window. These functions are modified with respect from the
13 | #' \href{https://github.com/ropenscilabs/ochRe}{ochRe package}.
14 | #'
15 | #' For more information about available cmapplot color palettes and how to apply
16 | #' them, see \code{vignette("colors")}.
17 | #'
18 | #' @describeIn viz_palette Displays the colors of any cmapplot palette
19 | #'
20 | #' @param pal character, name of a a cmapplot palette, or a vector of colors
21 | #' representing a palette
22 | #' @param ttl character, title to be displayed (the name of the palette)
23 | #' @param num numeric, the number of colors to display
24 | #'
25 | #' @examples
26 | #' # Visualize a single palette as individual colors
27 | #' viz_palette("legislation")
28 | #'
29 | #' # Print names and types of all available palettes
30 | #' as.data.frame(get_cmapplot_global("palettes")[1:2])
31 | #'
32 | #' @aliases cmap_palettes cmap_gradients cmap_colors
33 | #'
34 | #' @export
35 | viz_palette <- function(pal, ttl = NULL, num = NULL) {
36 |
37 | # if `pal` is a named CMAP palette of any type...
38 | if (fetch_pal(pal[1], return = "exists")) {
39 | # use the palette as the title (unless a custom title has been provided)
40 | if (is.null(ttl) | missing(ttl)){ ttl <- pal }
41 | # and extract the palette colors
42 | pal <- fetch_pal(pal)
43 | } else {
44 | # otherwise, use the object name as the title (unless a custom title has been provided)
45 | if (is.null(ttl) | missing(ttl)){ ttl <- deparse(substitute(pal)) }
46 | }
47 |
48 | # use the palette's intrinsic length (unless a custom length has been provided)
49 | if (is.null(num) | missing(num)){ num <- length(pal) }
50 |
51 | pal_func <- grDevices::colorRampPalette(pal)
52 | graphics::image(seq_len(num), 1, as.matrix(seq_len(num)), col = pal_func(num),
53 | main = paste0(ttl, " (", length(pal), " colors in palette, ",
54 | num, " displayed)"),
55 | xlab = "", ylab = "", xaxt = "n", yaxt = "n", bty = "n")
56 | }
57 |
58 | #' Discrete palette prep function
59 | #'
60 | #' @param palette Choose from 'cmap_palettes' list, or use one of the gradients
61 | #' defined in the 'cmap_gradients' list (gradients will be automatically
62 | #' converted into discrete bins)
63 | #' @param reverse Logical; reverse color order?cma
64 | #' @param ... Additional parameters passed on to the scale type
65 | #'
66 | #' @noRd
67 | cmap_pal_discrete <- function(palette = "main", reverse = FALSE) {
68 | pal <- fetch_pal(palette)
69 |
70 | if(palette == "race"){
71 | message("WARNING: The `race` palette should only be used with `cmap_fill_race()` or `cmap_color_race()`.")
72 | }
73 |
74 | if (reverse) {
75 | pal <- rev(pal)
76 | }
77 | return(scales::manual_pal(pal))
78 | }
79 |
80 | #' Apply discrete CMAP palettes to ggplot2 aesthetics
81 | #'
82 | #' Pick the function depending on the aesthetic of your ggplot object (fill or
83 | #' color). See \code{link{cmap_palettes}} for a listing of available gradients.
84 | #'
85 | #' @param palette Choose from 'cmap_palettes' list, or use one of the gradients
86 | #' defined in the 'cmap_gradients' list (gradients will be automatically
87 | #' converted into discrete bins)
88 | #' @param reverse Logical; reverse color order?
89 | #' @param ... Additional parameters passed on to the scale type
90 | #'
91 | #' @examples
92 | #' ggplot(pop_and_laborforce_by_age, aes(x = variable, y = value, fill = age)) +
93 | #' geom_col(position = position_stack(reverse = TRUE)) +
94 | #' facet_wrap(~year) +
95 | #' cmap_fill_discrete(palette = "community")
96 | #'
97 | #' ggplot(percentile_wages, aes(x = percentile, y = wage, color = cluster)) +
98 | #' geom_line() +
99 | #' cmap_color_discrete(palette = "prosperity")
100 | #'
101 | #' @describeIn cmap_fill_discrete For fill aesthetic
102 | #' @export
103 | cmap_fill_discrete <- function(palette = "main", reverse = FALSE, ...) {
104 | ggplot2::discrete_scale(
105 | "fill", "cmap_palettes",
106 | palette = cmap_pal_discrete(palette, reverse = reverse),
107 | ...
108 | )
109 | }
110 |
111 | #' @describeIn cmap_fill_discrete For color aesthetic
112 | #' @export
113 | cmap_color_discrete <- function(palette = "main", reverse = FALSE, ...) {
114 | ggplot2::discrete_scale(
115 | "colour", "cmap_palettes",
116 | palette = cmap_pal_discrete(palette, reverse = reverse),
117 | ...
118 | )
119 | }
120 |
121 | #' @describeIn cmap_fill_discrete For color aesthetic
122 | #' @export
123 | cmap_colour_discrete <- cmap_color_discrete
124 |
--------------------------------------------------------------------------------
/man/theme_cmap.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/theme_cmap.R
3 | \name{theme_cmap}
4 | \alias{theme_cmap}
5 | \title{Add CMAP theme to ggplot chart}
6 | \usage{
7 | theme_cmap(
8 | xlab = NULL,
9 | ylab = NULL,
10 | hline = NULL,
11 | vline = NULL,
12 | gridlines = c("h", "v", "hv", "none"),
13 | axislines = c("none", "x", "y", "xy"),
14 | axisticks = c("none", "x", "y", "xy"),
15 | show.legend = TRUE,
16 | legend.max.columns = NULL,
17 | debug = FALSE,
18 | overrides = list(),
19 | ...
20 | )
21 | }
22 | \arguments{
23 | \item{xlab, ylab}{Char, the string used to label the x and y axes,
24 | respectively. If unspecified, the axis label will be left off the graph. See
25 | details for unexpected outcomes when using these arguments along with
26 | \code{coord_flip()}.}
27 |
28 | \item{hline, vline}{Numeric, the location of a strong horizontal or vertical
29 | line to be added to the plot. Use \code{hline = 0}, for example, to place a
30 | line at y = 0 to differentiate between positive and negative values. The
31 | width of this line is determined by
32 | \code{cmapplot_globals$consts$lwd_strongline}. Note that on most displays
33 | the difference between this line and gridlines is impossible to discern in
34 | R. The difference will be visible upon export.}
35 |
36 | \item{gridlines}{Char, the grid lines to be displayed on the chart. If left as
37 | default, horizontal grid lines will be displayed while vertical grid lines
38 | will be masked. Acceptable values are "h" (horizontal only), "v" (vertical
39 | only), "hv" (both horizontal and vertical), and "none" (neither).}
40 |
41 | \item{axislines}{Char, the axis lines to be displayed on the chart. Acceptable
42 | values are "x" (x axis only), "y" (y axis only), "xy" (both axes), and
43 | "none" (neither, the default).}
44 |
45 | \item{axisticks}{Char, the axis ticks to be displayed on the chart. Acceptable
46 | values are "x" (x axis only), "y" (y axis only), "xy" (both axes), and
47 | "none" (neither, the default). Because \code{ggplot2} defaults to moderately
48 | expanding the range of displayed data, this may need to be accompanied by a
49 | call to \code{expand = c(0, 0)} within an appropriate \code{scale_*_*}
50 | argument in order for ticks to appear to touch the outermost gridline(s).}
51 |
52 | \item{show.legend}{Bool, \code{TRUE} is the default. \code{FALSE} to hide the
53 | legend.}
54 |
55 | \item{legend.max.columns}{Integer, the maximum number of columns in the
56 | legend. If no value is set, the chart will rely on `ggplot`'s default and
57 | automatic column handling behavior, which should work for most cases. Manual
58 | adjustment may be required if legend entries are particularly numerous
59 | and/or lengthy. Note that `ggplot` will still auto-adjust in ways that may
60 | mean the total number of columns is less than the maximum (e.g., if there
61 | are five items in a legend with four columns as the maximum, the output will
62 | be one row of three and another row of two).}
63 |
64 | \item{debug}{Bool, Defaults to \code{FALSE}. Set to \code{TRUE} to show
65 | rectangles around all \code{geom_rect()} elements for debugging.}
66 |
67 | \item{overrides}{Named list, overrides the default drawing attributes defined
68 | in \code{cmapplot_globals$consts} which are drawn by
69 | \code{\link{theme_cmap}}. Units are in bigpts (1/72 of an inch).}
70 |
71 | \item{...}{pass additional arguments to ggplot2's \code{\link[ggplot2]{theme}}
72 | function to override any elements of the default CMAP theme.}
73 | }
74 | \description{
75 | Return one or more ggplot objects that together construct a plot area in
76 | accordance with CMAP design standards.
77 | }
78 | \details{
79 | Using either the \code{xlab} or \code{ylab} argument, but not both, will have
80 | undesireable outcomes in a ggplot that also invokes \code{coord_flip()}. Under
81 | the hood, \code{theme_cmap(xlab = "foo")} both sets \code{ggplot2::xlab =
82 | "foo"} and 'turns on' the ggplot theme element \code{axis.title.x}. With
83 | \code{coord_flip()}, the xlab travels with the data (becoming the ylab) but
84 | the theme modifier stays on the x axis. To solve this, rewrite your ggplot
85 | construction to avoid \code{coord_flip()} or manually turn off and on the
86 | correct elements from ggplot2's \code{\link[ggplot2]{theme}} function in the
87 | \code{...} of this function.
88 | }
89 | \examples{
90 |
91 | \dontrun{
92 |
93 | # The only way to place the origin line (`hline`, `vline`) behind any data geoms
94 | # is to or place `theme_cmap()` before the geoms:
95 | ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
96 | theme_cmap(hline = 0, ylab = "Percent change") +
97 | geom_line() +
98 | scale_x_continuous(breaks = scales::breaks_pretty(11))
99 |
100 |
101 | df <- dplyr::filter(traded_emp_by_race, variable \%in\% c("SpecializedTraded",
102 | "UnspecializedTraded"))
103 |
104 | ggplot(df, aes(x = reorder(Race, -value), y = value, fill = variable)) +
105 | geom_col(position = position_stack(reverse = TRUE)) +
106 | scale_y_continuous(labels = scales::percent) +
107 | theme_cmap(hline = 0, ylab = "This is the y axis")
108 |
109 | ggplot(df, aes(y = reorder(Race, -value), x = value, fill = variable)) +
110 | geom_col(position = position_stack(reverse = TRUE)) +
111 | scale_x_continuous(labels = scales::percent) +
112 | theme_cmap(vline = 0, gridlines = "v")
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/R/RcppExports.R:
--------------------------------------------------------------------------------
1 | # Generated by using Rcpp::compileAttributes() -> do not edit by hand
2 | # Generator token: 10BE3573-1514-4C36-9D1C-5A225CD40393
3 |
4 | #' Euclidean distance between two points.
5 | #' @param a A point.
6 | #' @param b A point.
7 | #' @return The distance between two points.
8 | #' @noRd
9 | NULL
10 |
11 | #' Squared Euclidean distance between two points.
12 | #' @param a A point.
13 | #' @param b A point.
14 | #' @return The distance between two points.
15 | #' @noRd
16 | NULL
17 |
18 | #' Move a box into the area specificied by x limits and y limits.
19 | #' @param b A box like \code{c(x1, y1, x2, y2)}
20 | #' @param xlim A Point with limits on the x axis like \code{c(xmin, xmax)}
21 | #' @param ylim A Point with limits on the y axis like \code{c(xmin, xmax)}
22 | #' @param force Magnitude of the force (defaults to \code{1e-6})
23 | #' @noRd
24 | NULL
25 |
26 | #' Get the coordinates of the center of a box.
27 | #' @param b A box like \code{c(x1, y1, x2, y2)}
28 | #' @noRd
29 | NULL
30 |
31 | #' Test if a box overlaps another box.
32 | #' @param a A box like \code{c(x1, y1, x2, y2)}
33 | #' @param b A box like \code{c(x1, y1, x2, y2)}
34 | #' @noRd
35 | NULL
36 |
37 | #' Test if a box overlaps another box.
38 | #' @param a A box like \code{c(x1, y1, x2, y2)}
39 | #' @param b A box like \code{c(x1, y1, x2, y2)}
40 | #' @noRd
41 | NULL
42 |
43 | #' Compute the repulsion force upon point \code{a} from point \code{b}.
44 | #'
45 | #' The force decays with the squared distance between the points, similar
46 | #' to the force of repulsion between magnets.
47 | #'
48 | #' @param a A point like \code{c(x, y)}
49 | #' @param b A point like \code{c(x, y)}
50 | #' @param force Magnitude of the force (defaults to \code{1e-6})
51 | #' @param direction direction in which to exert force, either "both", "x", or "y"
52 | #' @noRd
53 | NULL
54 |
55 | #' Compute the spring force upon point \code{a} from point \code{b}.
56 | #'
57 | #' The force increases with the distance between the points, similar
58 | #' to Hooke's law for springs.
59 | #'
60 | #' @param a A point like \code{c(x, y)}
61 | #' @param b A point like \code{c(x, y)}
62 | #' @param force Magnitude of the force (defaults to \code{1e-6})
63 | #' @param direction direction in which to exert force, either "both", "x", or "y"
64 | #' @noRd
65 | NULL
66 |
67 | #' Euclidean distance between two points.
68 | #' @param a A numeric vector.
69 | #' @param b A numeric vector.
70 | #' @return The distance between two points.
71 | #' @noRd
72 | euclid <- function(a, b) {
73 | .Call('_ggrepel_euclid', PACKAGE = 'ggrepel', a, b)
74 | }
75 |
76 | #' Get the coordinates of the center of a box.
77 | #' @param b A box like \code{c(x1, y1, x2, y2)}
78 | #' @noRd
79 | centroid <- function(b, hjust, vjust) {
80 | .Call('_ggrepel_centroid', PACKAGE = 'ggrepel', b, hjust, vjust)
81 | }
82 |
83 | #' Find the intersections between a line and a rectangle.
84 | #' @param c A circle like \code{c(x, y, r)}
85 | #' @param r A rectangle like \code{c(x1, y1, x2, y2)}
86 | #' @noRd
87 | intersect_circle_rectangle <- function(c, r) {
88 | .Call('_ggrepel_intersect_circle_rectangle', PACKAGE = 'ggrepel', c, r)
89 | }
90 |
91 | #' Find the intersection between a line and a circle.
92 | #' @param p1 A point on the line like \code{c(x, y)}
93 | #' @param p2 A point at the circle's center
94 | #' @param r The circle's radius
95 | #' @noRd
96 | intersect_line_circle <- function(p1, p2, r) {
97 | .Call('_ggrepel_intersect_line_circle', PACKAGE = 'ggrepel', p1, p2, r)
98 | }
99 |
100 | #' Find the intersections between a line and a rectangle.
101 | #' @param p1 A point like \code{c(x, y)}
102 | #' @param p2 A point like \code{c(x, y)}
103 | #' @param b A rectangle like \code{c(x1, y1, x2, y2)}
104 | #' @noRd
105 | intersect_line_rectangle <- function(p1, p2, b) {
106 | .Call('_ggrepel_intersect_line_rectangle', PACKAGE = 'ggrepel', p1, p2, b)
107 | }
108 |
109 | select_line_connection <- function(p1, b) {
110 | .Call('_ggrepel_select_line_connection', PACKAGE = 'ggrepel', p1, b)
111 | }
112 |
113 | approximately_equal <- function(x1, x2) {
114 | .Call('_ggrepel_approximately_equal', PACKAGE = 'ggrepel', x1, x2)
115 | }
116 |
117 | #' Adjust the layout of a list of potentially overlapping boxes.
118 | #' @param data_points A numeric matrix with rows representing points like
119 | #' \code{rbind(c(x, y), c(x, y), ...)}
120 | #' @param point_size A numeric vector representing the sizes of data points.
121 | #' @param point_padding_x Padding around each data point on the x axis.
122 | #' @param point_padding_y Padding around each data point on the y axis.
123 | #' @param boxes A numeric matrix with rows representing boxes like
124 | #' \code{rbind(c(x1, y1, x2, y2), c(x1, y1, x2, y2), ...)}
125 | #' @param xlim A numeric vector representing the limits on the x axis like
126 | #' \code{c(xmin, xmax)}
127 | #' @param ylim A numeric vector representing the limits on the y axis like
128 | #' \code{c(ymin, ymax)}
129 | #' @param force Magnitude of the force (defaults to \code{1e-6})
130 | #' @param max_time Maximum number of seconds to try to resolve overlaps
131 | #' (defaults to 0.1)
132 | #' @param max_iter Maximum number of iterations to try to resolve overlaps
133 | #' (defaults to 2000)
134 | #' @noRd
135 | repel_boxes2 <- function(data_points, point_size, point_padding_x, point_padding_y, boxes, xlim, ylim, hjust, vjust, force_push = 1e-7, force_pull = 1e-7, max_time = 0.1, max_overlaps = 10, max_iter = 2000L, direction = "both", verbose = 0L) {
136 | .Call('_ggrepel_repel_boxes2', PACKAGE = 'ggrepel', data_points, point_size, point_padding_x, point_padding_y, boxes, xlim, ylim, hjust, vjust, force_push, force_pull, max_time, max_overlaps, max_iter, direction, verbose)
137 | }
138 |
139 |
--------------------------------------------------------------------------------
/R/cmapplot.R:
--------------------------------------------------------------------------------
1 | #' cmapplot
2 | #'
3 | #' This package contains extra palettes, themes and geoms for \pkg{ggplot2},
4 | #' based on Chicago Metropolitan Agency for Planning (CMAP) design guidelines.
5 | #'
6 | #' Detailed documentation can be viewed at
7 | #' \url{https://cmap-repos.github.io/cmapplot}.
8 | #'
9 | #' Please report issues and suggest improvements at
10 | #' \url{https://github.com/CMAP-REPOS/cmapplot/issues}.
11 | #'
12 | #' @name cmapplot
13 | #' @docType package
14 | #' @import dplyr ggplot2 graphics grDevices grid gridtext Rcpp ragg rlang scales systemfonts
15 | #' @importFrom glue glue glue_collapse
16 | #' @keywords internal
17 | "_PACKAGE"
18 |
19 |
20 | #' Update fonts based on system -- *must* be done with .onLoad()
21 | #'
22 | #' @noRd
23 | #' @import rstudioapi
24 | .onLoad <- function(...) {
25 |
26 | family <- name <- path <- NULL
27 |
28 | # If font registry already contains Whitney core, set use_whitney == TRUE
29 | fonts_present <- systemfonts::registry_fonts() %>%
30 | dplyr::filter(family %in% cmapplot_globals$preferred_font) %>%
31 | nrow() >= 12
32 |
33 | assign("use_whitney",
34 | fonts_present,
35 | envir = cmapplot_globals)
36 |
37 |
38 | # Else, find and register necessary Whitney variants using systemfonts (or,
39 | # alternatively, find them manually in ~/Library/Fonts). Then, if font
40 | # registry contains Whitney core, set use_whitney == TRUE.
41 | if(!get("use_whitney", envir = cmapplot_globals)){
42 | whitney_paths <- dplyr::filter(systemfonts::system_fonts(), family == "Whitney")
43 | whitney_paths <- whitney_paths[["path"]]
44 |
45 | # On some OSX systems (e.g. pkgdown GHA VM) system_fonts() cannot find fonts
46 | # installed in the user fonts directory. In any case where system_fonts()
47 | # sees no Whitney fonts, if `user_dir` exists, it too is checked for fonts.
48 | user_dir <- paste0(Sys.getenv("HOME"), "/Library/Fonts")
49 | if(length(whitney_paths) == 0 & dir.exists(user_dir)){
50 | whitney_paths <- list.files(user_dir, full.names = TRUE)
51 | whitney_paths <- grep("Whitney-", whitney_paths, value = TRUE)
52 | }
53 |
54 | # Register preferred fonts using the paths found above. This will only be
55 | # attempted if at least 10 paths are found, as 10 distinct faces are needed
56 | # to register all possible variants of the three needed fonts. If the
57 | # correct face cannot be found, `find_path` will error and the try object
58 | # will fail before `use_whitney` is set to TRUE.
59 | if (length(whitney_paths) >= 10){
60 | try({
61 |
62 | # register preferred strong font (Whitney Semibold), with variants
63 | systemfonts::register_font(
64 | name = cmapplot_globals$preferred_font$strong,
65 | plain = find_path("Whitney-Semibold-Adv", whitney_paths),
66 | bold = find_path("Whitney-Black-Adv", whitney_paths),
67 | italic = find_path("Whitney-SemiboldItal-Adv", whitney_paths),
68 | bolditalic = find_path("Whitney-BlackItal-Adv", whitney_paths)
69 | )
70 |
71 | # register preferred regular font (Whitney Medium), with variants
72 | systemfonts::register_font(
73 | name = cmapplot_globals$preferred_font$regular,
74 | plain = find_path("Whitney-Medium-Adv", whitney_paths),
75 | bold = find_path("Whitney-Bold-Adv", whitney_paths),
76 | italic = find_path("Whitney-MediumItal-Adv", whitney_paths),
77 | bolditalic = find_path("Whitney-BoldItal-Adv", whitney_paths)
78 | )
79 |
80 | # register preferred light font (Whitney Book), with variants
81 | systemfonts::register_font(
82 | name = cmapplot_globals$preferred_font$light,
83 | plain = find_path("Whitney-Book-Adv", whitney_paths),
84 | bold = find_path("Whitney-Semibold-Adv", whitney_paths),
85 | italic = find_path("Whitney-BookItal-Adv", whitney_paths),
86 | bolditalic = find_path("Whitney-SemiboldItal-Adv", whitney_paths)
87 | )
88 |
89 | packageStartupMessage(paste0(
90 | "cmapplot has registered the following fonts for use in this R session:\n ",
91 | paste(cmapplot_globals$preferred_font, collapse = ", ")
92 | ))
93 |
94 | assign("use_whitney",
95 | TRUE,
96 | envir = cmapplot_globals)
97 | })
98 | }
99 | }
100 |
101 | # If Whitney is available...
102 | if(get("use_whitney", envir = cmapplot_globals)){
103 | # ... Update font names
104 | assign("font",
105 | list(strong = list(family = cmapplot_globals$preferred_font$strong, face = "plain"),
106 | regular = list(family = cmapplot_globals$preferred_font$regular, face = "plain"),
107 | light = list(family = cmapplot_globals$preferred_font$light, face = "plain")),
108 | envir = cmapplot_globals)
109 |
110 | # ... and check on rstudio graphics
111 | if (rstudioapi::isAvailable()){
112 | if(rstudioapi::getVersion() > "1.4"){
113 | if(getOption("RStudioGD.backend", FALSE) != "ragg"){
114 | options(RStudioGD.backend = "ragg")
115 | packageStartupMessage(paste(
116 | "cmapplot has set RStudio graphics to `ragg` for the current session.",
117 | "You can make this change permanent:\n ",
118 | "Tools > Global Options > General > Graphics > Graphics Device > Backend == 'AGG'."
119 | ))
120 | }
121 | } else {
122 | packageStartupMessage(paste(
123 | "cmapplot requires RStudio v1.4 or greater to use Whitney fonts",
124 | "in the R plots window.\nPlease update RStudio."))
125 | }
126 | # If using vanilla R, encourage RStudio installation
127 | } else {
128 | packageStartupMessage(paste(
129 | "cmapplot requires RStudio to use Whitney fonts in the R plots window.\n ",
130 | "Please install RStudio. "))
131 | }
132 | # Otherwise, notify user
133 | } else {
134 | packageStartupMessage(
135 | "cmapplot cannot locate Whitney fonts, so CMAP themes will use your default sans-serif font."
136 | )
137 | }
138 |
139 | # Load CMAP preferred default.aes (can't be done until fonts are specified)
140 | assign("default_aes_cmap",
141 | init_cmap_default_aes(),
142 | envir = cmapplot_globals)
143 |
144 | # Cache existing default.aes
145 | assign("default_aes_cached",
146 | fetch_current_default_aes(),
147 | envir = cmapplot_globals)
148 | }
149 |
--------------------------------------------------------------------------------
/man/geom_pandemics.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geom_pandemics.R
3 | \name{geom_pandemics}
4 | \alias{geom_pandemics}
5 | \title{Add Pandemics to time series graphs}
6 | \usage{
7 | geom_pandemics(
8 | xformat = "numeric",
9 | text = TRUE,
10 | label = " Pandemic",
11 | ymin = -Inf,
12 | ymax = Inf,
13 | fill = "#002d49",
14 | text_nudge_x = 0.2,
15 | text_nudge_y = 0,
16 | show.legend = FALSE,
17 | rect_aes = NULL,
18 | text_aes = NULL,
19 | update_Pandemics = FALSE,
20 | show_ongoing = TRUE,
21 | ...
22 | )
23 | }
24 | \arguments{
25 | \item{xformat}{Char, a string indicating whether the x axis of the primary
26 | data being graphed is in integer or date format. This argument will
27 | currently accept one of \code{c("numeric", "date")}.}
28 |
29 | \item{text}{Logical, whether or not to include labels that identify each box
30 | as a Pandemic.}
31 |
32 | \item{label}{Char, the text to label each Pandemic. Defaults to " Pandemic".
33 | (The space is a more consistent y axix buffer than text_nudge_y because it
34 | not relative to the scale of the y axis.)}
35 |
36 | \item{ymin, ymax}{Numeric, The height of the Pandemic rectangles. Defaults to
37 | -Inf and +Inf. Override to the top and bottom gridlines to implement ideal
38 | CMAP design standards.}
39 |
40 | \item{fill}{Char, the fill color for the Pandemic rectangles. Defaults to
41 | \code{#002d49} for compliance with CMAP design standards.}
42 |
43 | \item{text_nudge_x, text_nudge_y}{Numeric, the amount to shift the labels along
44 | each axis. Defaults to 0.2 and 0, respectively. Note that these use the x
45 | and y scales so will need to be adjusted depending on what is being graphed.
46 | `text_nudge_y` only works when `ymax` is not set to `+Inf`, which is the
47 | default. Consider setting `ymax` equal to the top of your graph or top
48 | gridline as an additional argument in `geom_pandemics()`.}
49 |
50 | \item{show.legend}{Logical, whether to render the rectangles in the legend.
51 | Defaults to \code{FALSE}.}
52 |
53 | \item{rect_aes, text_aes}{Named list, additional aesthetics to send to the
54 | rectangle and text geoms, respectively.}
55 |
56 | \item{update_Pandemics}{Logical or data frame. \code{FALSE}, the default,
57 | relies on the package's built in Pandemics table, which was last updated in
58 | March 2021 and is loaded into the \code{sysdata.R} file located in the
59 | \code{R} directory. \code{TRUE} calls the function
60 | \code{update_Pandemics}, which attempts to fetch the current Pandemics
61 | table from the NBER website. A custom data table of Pandemics can also be
62 | passed to this argument, but it must be structured identically to the
63 | five-column data table described in the the documentation file for the
64 | function \code{update_Pandemics}.}
65 |
66 | \item{show_ongoing}{Logical. \code{TRUE}, the default, will display an ongoing
67 | Pandemic that does not yet have a defined end date. If an ongoing Pandemic
68 | exists, it will be displayed as extending through the maximum extent of the
69 | graph's data (up to 2200). \code{FALSE} will remove the ongoing Pandemic
70 | from the graph.}
71 |
72 | \item{...}{additional aesthetics to send to BOTH the rectangle and text geoms.}
73 | }
74 | \description{
75 | \code{geom_pandemics} returns one or two ggplot geoms that add rectangles
76 | representing Pandemics to a plot. It will either return only rectangles or,
77 | by default, both rectangles and text identifying each Pandemic.
78 | }
79 | \section{Important notes}{
80 | If \code{show.legend = TRUE} you must place any
81 | categorical aesthetics (e.g. color, size) specific to the primary data in
82 | the geom(s) used to display that data. Otherwise, the legend will inherit
83 | aesthetics from geom_pandemics.
84 |
85 | It is best to place this object before your primary geom (likely
86 | \code{geom_line()}) in your code, so that ggplot draws it behind the primary
87 | data being drawn.
88 | }
89 |
90 | \section{Default color}{
91 | The CMAP color palette gray used for Pandemics is
92 | \code{#e3e8eb}. The rectangle geom has default fill and alpha values of
93 | \code{#002d49} and \code{0.11} built into the function. These replicate the
94 | palette color at the highest possible transparency. This is done because
95 | there is no known way to place the Pandemic geom behind the graph's grid
96 | lines. The default therefore produces the approved CMAP color while altering
97 | the appearance of any overlapping grid lines as little as possible. These
98 | can be overridden, but separately. Override fill using the top-level
99 | argument, as in \code{fill = "red"}. Override alpha within rect_aes as in
100 | \code{rect_aes = list(alpha = 0.5)}. Color and alpha were calculated using
101 | the hints found here:
102 | \url{https://stackoverflow.com/questions/6672374/convert-rgb-to-rgba-over-white}.
103 | }
104 |
105 | \section{Under the hood}{
106 | This function calls two custom geoms, constructed
107 | with ggproto. The custom GeomPandemics and GeomPandemicsText are modified
108 | versions of GeomRect and GeomText, respectively. The only variations to each
109 | occur in \code{default_aes}, \code{required_aes}, and \code{setup_data}
110 | arguments. These variations allow the the primary dataframe (specified in
111 | \code{ggplot(data = XXX)}) to filter the Pandemics displayed.
112 | }
113 |
114 | \examples{
115 | grp_goods <- dplyr::filter(grp_over_time, category == "Goods-Producing")
116 | grp_goods <- dplyr::mutate(grp_goods, year2 = as.Date(lubridate::date_decimal(year)))
117 |
118 | # INTEGER X AXIS:
119 | ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
120 | geom_pandemics() +
121 | geom_line() +
122 | scale_x_continuous("Year") +
123 | theme_minimal()
124 |
125 | # DATE X AXIS:
126 | ggplot(data = grp_goods,
127 | mapping = aes(x = year2, y = realgrp, color = cluster)) +
128 | geom_pandemics(xformat = "date") +
129 | geom_line() +
130 | scale_x_date("Year") +
131 | theme_minimal()
132 |
133 | # MODIFIED AESTHETICS:
134 | ggplot(grp_over_time, aes(x = year, y = realgrp)) +
135 | geom_pandemics(show.legend = TRUE, fill = "blue", text = FALSE,
136 | rect_aes = list(alpha = 1, color = "red")) +
137 | geom_line(aes(color = cluster)) +
138 | scale_x_continuous("Year") +
139 | theme_minimal()
140 |
141 | }
142 | \seealso{
143 | \itemize{ \item \url{https://ggplot2-book.org/extensions.html} \item
144 | \url{https://github.com/brodieG/ggbg/blob/development/inst/doc/extensions.html#stat-compute}
145 | \item \url{https://rpubs.com/hadley/97970} \item
146 | \url{https://ggplot2.tidyverse.org/articles/extending-ggplot2.html} }
147 | }
148 |
--------------------------------------------------------------------------------
/man/geom_text_lastonly.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geom_text_lastonly.R
3 | \name{geom_text_lastonly}
4 | \alias{geom_text_lastonly}
5 | \title{Text (Last Only)}
6 | \usage{
7 | geom_text_lastonly(
8 | mapping = NULL,
9 | data = NULL,
10 | stat = "identity",
11 | position = NULL,
12 | parse = FALSE,
13 | nudge_x = 0.25,
14 | nudge_y = 0,
15 | check_overlap = FALSE,
16 | na.rm = FALSE,
17 | show.legend = FALSE,
18 | inherit.aes = TRUE,
19 | add_points = FALSE,
20 | text_aes = NULL,
21 | point_aes = NULL,
22 | ...
23 | )
24 | }
25 | \arguments{
26 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2:aes]{aes()}}. If specified and
27 | \code{inherit.aes = TRUE} (the default), it is combined with the default mapping
28 | at the top level of the plot. You must supply \code{mapping} if there is no plot
29 | mapping.}
30 |
31 | \item{data}{The data to be displayed in this layer. There are three
32 | options:
33 |
34 | If \code{NULL}, the default, the data is inherited from the plot
35 | data as specified in the call to \code{\link[ggplot2:ggplot]{ggplot()}}.
36 |
37 | A \code{data.frame}, or other object, will override the plot
38 | data. All objects will be fortified to produce a data frame. See
39 | \code{\link[ggplot2:fortify]{fortify()}} for which variables will be created.
40 |
41 | A \code{function} will be called with a single argument,
42 | the plot data. The return value must be a \code{data.frame}, and
43 | will be used as the layer data. A \code{function} can be created
44 | from a \code{formula} (e.g. \code{~ head(.x, 10)}).}
45 |
46 | \item{stat}{The statistical transformation to use on the data for this layer.
47 | When using a \verb{geom_*()} function to construct a layer, the \code{stat}
48 | argument can be used to override the default coupling between geoms and
49 | stats. The \code{stat} argument accepts the following:
50 | \itemize{
51 | \item A \code{Stat} ggproto subclass, for example \code{StatCount}.
52 | \item A string naming the stat. To give the stat as a string, strip the
53 | function name of the \code{stat_} prefix. For example, to use \code{stat_count()},
54 | give the stat as \code{"count"}.
55 | \item For more information and other ways to specify the stat, see the
56 | \link[ggplot2:layer_stats]{layer stat} documentation.
57 | }}
58 |
59 | \item{position}{Position adjustment, either as a string, or the result of a
60 | call to a position adjustment function. Cannot be jointy specified with
61 | \code{nudge_x} or \code{nudge_y}.}
62 |
63 | \item{parse}{If \code{TRUE}, the labels will be parsed into expressions and
64 | displayed as described in \code{?plotmath}.}
65 |
66 | \item{nudge_x, nudge_y}{Horizontal and vertical adjustment to nudge labels by.
67 | Useful for offsetting text from points, particularly on discrete scales.
68 | Cannot be jointy specified with \code{position}.}
69 |
70 | \item{check_overlap}{If \code{TRUE}, text that overlaps previous text in the
71 | same layer will not be plotted. \code{check_overlap} happens at draw time
72 | and in the order of the data. Therefore data should be arranged by the
73 | label column before calling \code{geom_text_lastonly()}.}
74 |
75 | \item{na.rm}{If \code{FALSE}, the default, missing values are removed with
76 | a warning. If \code{TRUE}, missing values are silently removed.}
77 |
78 | \item{show.legend}{logical. Should this layer be included in the legends?
79 | \code{NA}, the default, includes if any aesthetics are mapped.
80 | \code{FALSE} never includes, and \code{TRUE} always includes.
81 | It can also be a named logical vector to finely select the aesthetics to
82 | display. To include legend keys for all levels, even
83 | when no data exists, use \code{TRUE}. If \code{NA}, all levels are shown in legend,
84 | but unobserved levels are omitted.}
85 |
86 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
87 | rather than combining with them. This is most useful for helper functions
88 | that define both data and aesthetics and shouldn't inherit behaviour from
89 | the default plot specification, e.g. \code{\link[ggplot2:annotation_borders]{annotation_borders()}}.}
90 |
91 | \item{add_points}{If \code{TRUE}, points will be added to the plot (for the
92 | labeled data only). Default size=2, color will match line color.}
93 |
94 | \item{text_aes, point_aes}{Named list, additional aesthetics to send to the
95 | text and point geoms, respectively.}
96 |
97 | \item{...}{Additional aesthetics to send to BOTH the point and text geoms.
98 | Note that if \code{add_points = FALSE}, additional parameters can be passed
99 | to the text geom here, rather than in \code{text_aes}, without breaking.}
100 | }
101 | \description{
102 | Label only the last point(s) on a plot. \code{geom_text_lastonly()} can be
103 | used instead of \code{ggplot2::geom_text()} when only the last point(s)
104 | should be labeled. This is accomplished by identifying the maximum value of
105 | \code{x} in \code{data} and applying a filter to omit records where \code{x}
106 | is less than the maximum.
107 | }
108 | \details{
109 | Labels are placed by default to the right of the final point, and may be
110 | partially cut off by the plot limits. There are two known ways to address
111 | this: \enumerate{ \item Turn off panel clipping, e.g. with
112 | \code{coord_cartesian(clip = "off")}. Substitute the correct coordinate
113 | system for your plot--all have a \code{clip} argument available. Note that
114 | this will allow all geoms in the plot to draw outside the panel area, which
115 | may have unintended consequences. \item Manually expand the \code{x} scale,
116 | e.g. with \code{scale_x_continuous(expand=expand_scale(mult=0.10))} or
117 | \code{coord_cartesian(xlim = c(min, max))}. }
118 |
119 | Code was mostly copied from the source of \code{ggplot2::geom_text()} and
120 | \code{ggplot2::geom_point()}.
121 | }
122 | \examples{
123 | df <- data.frame(year=2010:2020, value=runif(22), var=c(rep("A", 11), rep("B", 11)))
124 |
125 | # Without points, label formatting or x-axis expansion
126 | ggplot(df, aes(x=year, y=value, color=var)) +
127 | geom_line() +
128 | labs(title="Random lines") +
129 | scale_y_continuous("Percentage of absolutely nothing") +
130 | scale_x_continuous("Year") +
131 | geom_text_lastonly()
132 |
133 | # With points, label formatting and x-axis expansion
134 | ggplot(df, aes(x=year, y=value, color=var, label=sprintf("\%.1f\%\%", 100*value))) +
135 | geom_line() +
136 | labs(title="Random lines") +
137 | scale_y_continuous("Percentage of absolutely nothing", labels=scales::percent) +
138 | scale_x_continuous("Year", expand=expansion(mult=c(0.05, 0.10))) +
139 | geom_text_lastonly(add_points=TRUE, text_aes=list(fontface="bold"), point_aes=list(size=2.5))
140 |
141 | }
142 |
--------------------------------------------------------------------------------
/man/finalize_plot.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/finalize_plot.R
3 | \name{finalize_plot}
4 | \alias{finalize_plot}
5 | \title{Arrange and save CMAP ggplot chart}
6 | \usage{
7 | finalize_plot(
8 | plot = NULL,
9 | title = "",
10 | caption = "",
11 | width = 670/72,
12 | height = 400/72,
13 | sidebar_width = NULL,
14 | caption_align = 0,
15 | mode = c("plot"),
16 | filename = NULL,
17 | overwrite = FALSE,
18 | ppi = 300,
19 | fill_bg = "white",
20 | fill_canvas = "gray90",
21 | overrides = list(),
22 | inherit = c("tc", "t", "c", "none"),
23 | legend_shift = TRUE,
24 | debug = FALSE,
25 | use_cmap_aes = TRUE,
26 | caption_valign,
27 | title_width,
28 | ...
29 | )
30 | }
31 | \arguments{
32 | \item{plot}{ggplot object, the variable name of the plot you have created that
33 | you want to finalize. If null (the default), the most recent plot will be
34 | retrieved via \code{ggplot2::last_plot()}.}
35 |
36 | \item{title, caption}{Char, the text you want to appear in the title and
37 | caption blocks. If empty, any non-Null values from \code{plot} will be
38 | retrieved. These blocks take html formatting, so manual text breaks can be
39 | created with \code{
} and formatting can be changed with \code{}.}
40 |
41 | \item{width, height}{Numeric, the dimensions for the output image, including
42 | the title. Units in inches, which interacts with \code{ppi} to define the
43 | pixel dimensions of raster outputs. Default is 9.31 inches wide (670/72) and
44 | 5.56 inches tall (400/72), to match Comms specification for web graphics.}
45 |
46 | \item{sidebar_width}{Numeric, the width in inches for the sidebar. If
47 | unspecified, use 25 percent of the total output width (per Comms guidance).
48 | If set to 0, the title, if present, is moved above the topline and the
49 | caption, if present, is moved to below the plot.}
50 |
51 | \item{caption_align}{Numeric, alignment of the caption text. When the caption
52 | is in the title column (when \code{sidebar_width > 0}), 0 (the default)
53 | aligns text to bottom; 1 aligns top. When the caption is located below the
54 | plot, 0 aligns left and 1 aligns right. 0.5 aligns center.}
55 |
56 | \item{mode}{Vector, the action(s) to be taken with the plot. View in R with
57 | \code{plot}, the default. Save using any of the following: \code{png},
58 | \code{tiff}, \code{jpeg}, \code{svg}, \code{pdf}, \code{ps}. Run
59 | multiple simultaneous outputs with a vector, e.g. \code{c("plot", "png",
60 | "pdf")}.}
61 |
62 | \item{filename}{Char, the file path and name you want the plot to be saved to.
63 | You may specify an extension to use. If you don't, the correct extension
64 | will be added for you.}
65 |
66 | \item{overwrite}{Bool, set to \code{TRUE} if you would like the function to
67 | overwrite existing files by the same name. The default is \code{FALSE}.}
68 |
69 | \item{ppi}{Numeric, the resolution of exported images (pixels per inch).
70 | Default = 300.}
71 |
72 | \item{fill_bg, fill_canvas}{Char, strings that represent colors R can
73 | interpret. They are used to fill behind and around the finished plot,
74 | respectively.}
75 |
76 | \item{overrides}{Named list, overrides the default drawing attributes defined
77 | in \code{cmapplot_globals$consts} which are drawn by
78 | \code{\link{finalize_plot}}. Units are in bigpts (1/72 of an inch).}
79 |
80 | \item{inherit}{Char, a string of characters that represent which elements of
81 | the underlying ggplot object the function should attempt to inherit if not
82 | specified in this function. If left as default, the function will attempt to
83 | replace blank titles and captions with those from the underlying plot
84 | object. Acceptable values are "t" (inherit title only), "c" (inherit caption
85 | only), "tc" (the default, inherit both title and caption), and "none"
86 | (inherit nothing).}
87 |
88 | \item{legend_shift}{Bool, \code{TRUE}, the default, attempts to align the
89 | legend all the way left (on top of the y axis labels) per CMAP design
90 | standards. \code{FALSE} maintains the alignment used in the original plot.}
91 |
92 | \item{debug}{Bool, \code{TRUE} enables outlines around components of finalized
93 | plot. Defaults to \code{FALSE}.}
94 |
95 | \item{use_cmap_aes}{Bool, \code{TRUE}, the default, temporarily implements
96 | CMAP default aesthetic settings for geoms (see
97 | \code{\link{apply_cmap_default_aes}}) for the present plot.}
98 |
99 | \item{caption_valign}{This is deprecated as of cmapplot 1.1.0 and will be
100 | removed in future releases. Replace with \code{caption_align} argument.}
101 |
102 | \item{title_width}{This is deprecated as of cmapplot 1.1.1 and will be removed
103 | in future releases. Replace with \code{sidebar_width} argument.}
104 |
105 | \item{...}{Pass additional arguments to ggplot2's \code{\link[ggplot2]{theme}}
106 | function to override any elements of the plot's theme when drawing.}
107 | }
108 | \value{
109 | This function invisibly returns the finished graphic as a gTree
110 | object. If stored (e.g. \code{g <- finalize_plot(...)}), the gTree can be
111 | drawn later with \code{grid} (e.g. \code{grid::grid.draw(g)}).
112 | }
113 | \description{
114 | Place a ggplot into a frame defined by CMAP design standards. It will align
115 | your title and caption to the left, add a horizontal line on top, and make
116 | other adjustments. It can show you the final plot and/or export it as a raster
117 | or vector file. This function will not apply CMAP design standards to the plot
118 | itself: use with \code{theme_cmap()} for that. This function uses ragg drivers
119 | in R and for raster exports, svg for svg, and cairo_pdf for PDFs.
120 | }
121 | \examples{
122 | \dontrun{
123 | econ_plot <- ggplot(data = cluster_jobchange,
124 | mapping = aes(
125 | y = reorder(name, jobchange),
126 | x = jobchange,
127 | fill = category)) +
128 | geom_col() +
129 | theme_cmap(gridlines = "v", vline = 0) +
130 | scale_x_continuous(labels = scales::comma)
131 |
132 | finalize_plot(econ_plot,
133 | "Cluster-level employment changes in the Chicago MSA, 2001-17",
134 | "Source: Chicago Metropolitan Agency for Planning analysis",
135 | mode = "plot",
136 | height = 6,
137 | width = 8,
138 | sidebar_width = 2.5,
139 | overrides = list(margin_plot_r = 30))
140 |
141 | transit_plot <- transit_ridership \%>\%
142 | mutate(system = case_when(
143 | system == "cta_bus" ~ "CTA (Bus)",
144 | system == "cta_rail" ~ "CTA (Rail)",
145 | system == "metra" ~ "Metra",
146 | system == "pace" ~ "Pace",
147 | system == "pace_ada" ~ "Paratransit"
148 | )) \%>\%
149 | ggplot(aes(x = year, y = ridership, color = system)) +
150 | geom_line() +
151 | theme_cmap(legend.max.columns = 3)
152 |
153 | finalize_plot(transit_plot,
154 | "Transit ridership in the RTA region over time, 1980-2019
155 | (in millions)",
156 | "Source: Chicago Metropolitan Agency for Planning
157 | analysis of data from the Regional Transportation Authority",
158 | mode=c("plot", "pdf"),
159 | filename = "foo")
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/man/geom_recessions.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geom_recessions.R
3 | \name{geom_recessions}
4 | \alias{geom_recessions}
5 | \title{Add recessions to time series graphs}
6 | \usage{
7 | geom_recessions(
8 | xformat = "numeric",
9 | text = TRUE,
10 | label = " Recession",
11 | ymin = -Inf,
12 | ymax = Inf,
13 | fill = "#002d49",
14 | text_nudge_x = 0.2,
15 | text_nudge_y = 0,
16 | show.legend = FALSE,
17 | rect_aes = NULL,
18 | text_aes = NULL,
19 | update_recessions = FALSE,
20 | show_ongoing = TRUE,
21 | ...
22 | )
23 | }
24 | \arguments{
25 | \item{xformat}{Char, a string indicating whether the x axis of the primary
26 | data being graphed is in integer or date format. This argument will
27 | currently accept one of \code{c("numeric", "date")}.}
28 |
29 | \item{text}{Logical, whether or not to include labels that identify each box
30 | as a recession.}
31 |
32 | \item{label}{Char, the text to label each recession. Defaults to " Recession".
33 | (The space is a more consistent y axix buffer than text_nudge_y because it
34 | not relative to the scale of the y axis.)}
35 |
36 | \item{ymin, ymax}{Numeric, The height of the recession rectangles. Defaults to
37 | -Inf and +Inf. Override to the top and bottom gridlines to implement ideal
38 | CMAP design standards.}
39 |
40 | \item{fill}{Char, the fill color for the recession rectangles. Defaults to
41 | \code{#002d49} for compliance with CMAP design standards.}
42 |
43 | \item{text_nudge_x, text_nudge_y}{Numeric, the amount to shift the labels along
44 | each axis. Defaults to 0.2 and 0, respectively. Note that these use the x
45 | and y scales so will need to be adjusted depending on what is being graphed.
46 | `text_nudge_y` only works when `ymax` is not set to `+Inf`, which is the
47 | default. Consider setting `ymax` equal to the top of your graph or top
48 | gridline as an additional argument in `geom_recessions()`.}
49 |
50 | \item{show.legend}{Logical, whether to render the rectangles in the legend.
51 | Defaults to \code{FALSE}.}
52 |
53 | \item{rect_aes, text_aes}{Named list, additional aesthetics to send to the
54 | rectangle and text geoms, respectively.}
55 |
56 | \item{update_recessions}{Logical or data frame. \code{FALSE}, the default,
57 | relies on the package's built in recessions table, which was last updated in
58 | March 2021 and is loaded into the \code{sysdata.R} file located in the
59 | \code{R} directory. \code{TRUE} calls the function
60 | \code{update_recessions}, which attempts to fetch the current recessions
61 | table from the NBER website. A custom data table of recessions can also be
62 | passed to this argument, but it must be structured identically to the
63 | five-column data table described in the the documentation file for the
64 | function \code{update_recessions}.}
65 |
66 | \item{show_ongoing}{Logical. \code{TRUE}, the default, will display an ongoing
67 | recession that does not yet have a defined end date. If an ongoing recession
68 | exists, it will be displayed as extending through the maximum extent of the
69 | graph's data (up to 2200). \code{FALSE} will remove the ongoing recession
70 | from the graph.}
71 |
72 | \item{...}{additional aesthetics to send to BOTH the rectangle and text geoms.}
73 | }
74 | \description{
75 | \code{geom_recessions} returns one or two ggplot geoms that add rectangles
76 | representing recessions to a plot. It will either return only rectangles or,
77 | by default, both rectangles and text identifying each recession.
78 | }
79 | \section{Important notes}{
80 | If \code{show.legend = TRUE} you must place any
81 | categorical aesthetics (e.g. color, size) specific to the primary data in
82 | the geom(s) used to display that data. Otherwise, the legend will inherit
83 | aesthetics from geom_recessions.
84 |
85 | It is best to place this object before your primary geom (likely
86 | \code{geom_line()}) in your code, so that ggplot draws it behind the primary
87 | data being drawn.
88 | }
89 |
90 | \section{Default color}{
91 | The CMAP color palette gray used for recessions is
92 | \code{#e3e8eb}. The rectangle geom has default fill and alpha values of
93 | \code{#002d49} and \code{0.11} built into the function. These replicate the
94 | palette color at the highest possible transparency. This is done because
95 | there is no known way to place the recession geom behind the graph's grid
96 | lines. The default therefore produces the approved CMAP color while altering
97 | the appearance of any overlapping grid lines as little as possible. These
98 | can be overridden, but separately. Override fill using the top-level
99 | argument, as in \code{fill = "red"}. Override alpha within rect_aes as in
100 | \code{rect_aes = list(alpha = 0.5)}. Color and alpha were calculated using
101 | the hints found here:
102 | \url{https://stackoverflow.com/questions/6672374/convert-rgb-to-rgba-over-white}.
103 | }
104 |
105 | \section{Under the hood}{
106 | This function calls two custom geoms, constructed
107 | with ggproto. The custom GeomRecessions and GeomRecessionsText are modified
108 | versions of GeomRect and GeomText, respectively. The only variations to each
109 | occur in \code{default_aes}, \code{required_aes}, and \code{setup_data}
110 | arguments. These variations allow the the primary dataframe (specified in
111 | \code{ggplot(data = XXX)}) to filter the recessions displayed.
112 | }
113 |
114 | \examples{
115 | grp_goods <- dplyr::filter(grp_over_time, category == "Goods-Producing")
116 | grp_goods <- dplyr::mutate(grp_goods, year2 = as.Date(lubridate::date_decimal(year)))
117 |
118 | # INTEGER X AXIS:
119 | ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
120 | geom_recessions() +
121 | geom_line() +
122 | scale_x_continuous("Year") +
123 | theme_minimal()
124 |
125 | # DATE X AXIS:
126 | ggplot(data = grp_goods,
127 | mapping = aes(x = year2, y = realgrp, color = cluster)) +
128 | geom_recessions(xformat = "date") +
129 | geom_line() +
130 | scale_x_date("Year") +
131 | theme_minimal()
132 |
133 | # MODIFIED AESTHETICS:
134 | ggplot(grp_over_time, aes(x = year, y = realgrp)) +
135 | geom_recessions(show.legend = TRUE, fill = "blue", text = FALSE,
136 | rect_aes = list(alpha = 1, color = "red")) +
137 | geom_line(aes(color = cluster)) +
138 | scale_x_continuous("Year") +
139 | theme_minimal()
140 |
141 |
142 | # BELOW EXAMPLES SHOW MORE THAN 1 RECESSION
143 | df <- data.frame(year_dec=1950:1999, value=rnorm(100), var=c(rep("A", 50), rep("B", 50)))
144 | df$year_date <- as.Date(lubridate::date_decimal(df$year_dec))
145 |
146 | # A plot with an integer-based x axis
147 | ggplot(df, mapping = aes(x = year_dec, y = value)) +
148 | geom_recessions() +
149 | geom_line(aes(color = var)) +
150 | scale_x_continuous("Year") +
151 | theme_minimal()
152 |
153 | # A plot with a date-based x axis
154 | ggplot(df, mapping = aes(x = year_date, y = value)) +
155 | geom_recessions(xformat = "date", show.legend = TRUE) +
156 | geom_line(aes(color = var)) +
157 | scale_x_date() +
158 | theme_minimal()
159 |
160 | }
161 | \seealso{
162 | \itemize{ \item \url{https://ggplot2-book.org/extensions.html} \item
163 | \url{https://github.com/brodieG/ggbg/blob/development/inst/doc/extensions.html#stat-compute}
164 | \item \url{https://rpubs.com/hadley/97970} \item
165 | \url{https://ggplot2.tidyverse.org/articles/extending-ggplot2.html} }
166 | }
167 |
--------------------------------------------------------------------------------
/README.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | output: github_document
3 | ---
4 |
5 |
32 |
33 | ```{r setup, include = FALSE}
34 | knitr::opts_chunk$set(
35 | collapse = TRUE,
36 | comment = "#>",
37 | fig.path = "man/figures/README-",
38 | fig.width = 7,
39 | fig.asp = 400/670,
40 | fig.retina = 4,
41 | fig.align = "center",
42 | dev = "ragg_png"
43 | )
44 |
45 | devtools::load_all()
46 | library(tidyverse)
47 | ```
48 |
49 | # cmapplot
50 |
51 |
52 | [](https://github.com/CMAP-REPOS/cmapplot/actions?query=workflow%3AR-CMD-check)
53 | [](https://github.com/CMAP-REPOS/cmapplot/actions?query=workflow%3Apkgdown)
54 |
55 |
56 | This R package provides themes, color scales, and other custom functions for [ggplot2](https://github.com/tidyverse/ggplot2), based on Chicago Metropolitan Agency for Planning (CMAP) design guidelines.
57 |
58 | CMAP staff who are interested in using this package, or merely staying in the loop, are encouraged to join the [R team](https://teams.microsoft.com/l/team/19%3ad705bfd7596a4518b588ad529d2367c8%40thread.skype/conversations?groupId=d7bab529-9c30-441e-9db6-4edfdca8202c&tenantId=43b185b9-e6d9-45a5-8e36-4c08dc0ab1a2) in Microsoft Teams and follow the "cmapplot" channel.
59 |
60 |
61 | ## The basics
62 | The cmapplot package contains a few key components:
63 |
64 | 1. Apply a CMAP theme to ggplots with `theme_cmap()`
65 | 2. Easily provide common CMAP plot customizations, such as with custom geoms `geom_recessions()` and `geom_text_lastonly()`
66 | 3. Apply CMAP colors using a variety of custom functions (e.g. `cmap_fill_discrete()`)
67 | 4. Place the themed plot within a CMAP layout, and export the plot from R if desired with `finalize_plot()`
68 |
69 |
70 | ## Installation
71 |
72 | Run the following to install or update cmapplot:
73 |
74 | ```{r install, eval=FALSE, message=FALSE, warning=FALSE}
75 | ## Install current version from GitHub
76 | devtools::install_github("CMAP-REPOS/cmapplot", build_vignettes=TRUE)
77 |
78 | ## Then load the package as you would any other
79 | library(cmapplot)
80 | ```
81 |
82 | For more detailed information about installing the package, particularly on a CMAP-issued computer, see [this article](https://cmap-repos.github.io/cmapplot/articles/installation.html).
83 |
84 | To install on macOS, users must install [XQuartz](https://www.xquartz.org) before cmapplot can be loaded. (This can be easily accomplished via the [Homebrew](https://brew.sh) package manager with the command `brew install --cask xquartz`.)
85 |
86 | **A note about fonts**: The cmapplot package works best when installed on a computer with the Whitney family of fonts installed (specifically the Book, Medium, and Semibold variants). If installed on a computer *without* Whitney, the package will still work, but the fonts will default to your computer's default sans-serif font (probably Arial).
87 |
88 |
89 | ## CMAP theme and colors
90 |
91 | The function `theme_cmap()` returns a complete ggplot2 theme that can be added to a ggplot code block (similar to `ggplot2::theme_minimal()` or `ggplot2::theme_bw()`). Additionally, `theme_cmap()` accepts a variety of arguments to additionally customize the theme output. CMAP color functions apply colors from the CMAP color palette to the plot.
92 |
93 | ```{r theme, message=FALSE}
94 | ggplot(data = pop_and_laborforce_by_age,
95 | aes(x = value,
96 | y = interaction(year, variable, sep = " "),
97 | fill = age)) +
98 | geom_col(position = position_stack(reverse = TRUE)) +
99 | scale_x_continuous(labels = scales::percent) +
100 | theme_cmap(xlab = "Percent",
101 | gridlines = "v",
102 | vline = 0) +
103 | cmap_fill_discrete(palette = "environment")
104 | ```
105 |
106 |
107 | ## Finalizing the plot
108 |
109 | The function `finalize_plot()` places a ggplot within a frame defined by CMAP design standards. It provides a variety of customization options via arguments, and allows for in-R viewing and/or exporting in various formats.
110 |
111 | ```{r finalize, message=FALSE}
112 | finalize_plot(title = "Regional population and labor force participation",
113 | caption = "Data from the American Community Survey",
114 | width = 7, height = 4.25)
115 | ```
116 |
117 |
118 | ## Additional reading
119 |
120 | While this package is designed to make the application of CMAP design standards to plots relatively easy, developing a professional, finished plot in R will require a decent familiarity with the grammar of [ggplot2](ggplot2.tidyverse.org/). Excellent resources in this category already exist:
121 |
122 | - The [R graphics cookbook](https://r-graphics.org/) provides accessible examples of how to make almost [any type](https://r-graphics.org/recipe-miscgraph-vectorfield) of plot, as well as how to modify things like [limits, scales](https://r-graphics.org/recipe-axes-range), [coordinate systems](https://r-graphics.org/recipe-axes-polar), and [facets](https://r-graphics.org/recipe-facet-basic).
123 | - The [ggplot2 book](https://ggplot2-book.org/) delves deeper into why and how ggplot2 works the way it does, also with distinct chapters on topics like [scales](https://ggplot2-book.org/scales-guides.html), [coordinate systems](https://ggplot2-book.org/coord.html), [facets](https://ggplot2-book.org/facet.html), etc.
124 | - The [ggplot2](ggplot2.tidyverse.org/) website.
125 | - The [R for Data Science (R4DS)](https://r4ds.had.co.nz/) book, especially the [Graphics for Communication](https://r4ds.had.co.nz/graphics-for-communication.html) chapter.
126 |
--------------------------------------------------------------------------------
/man/geom_text_lastonly_repel.Rd:
--------------------------------------------------------------------------------
1 | % Generated by roxygen2: do not edit by hand
2 | % Please edit documentation in R/geom_text_lastonly_repel.R
3 | \name{geom_text_lastonly_repel}
4 | \alias{geom_text_lastonly_repel}
5 | \title{Text (Last Only) Repel}
6 | \usage{
7 | geom_text_lastonly_repel(
8 | mapping = NULL,
9 | data = NULL,
10 | stat = "identity",
11 | position = NULL,
12 | parse = FALSE,
13 | box.padding = 0.25,
14 | point.padding = 1e-06,
15 | min.segment.length = 0.5,
16 | arrow = NULL,
17 | force = 1,
18 | force_pull = 1,
19 | max.time = 0.5,
20 | max.iter = 10000,
21 | max.overlaps = getOption("ggrepel.max.overlaps", default = 10),
22 | nudge_x = 0.4,
23 | nudge_y = 0,
24 | xlim = c(NA, NA),
25 | ylim = c(NA, NA),
26 | na.rm = FALSE,
27 | direction = c("y", "x", "both"),
28 | seed = NA,
29 | verbose = FALSE,
30 | show.legend = FALSE,
31 | inherit.aes = TRUE,
32 | add_points = FALSE,
33 | text_aes = NULL,
34 | point_aes = NULL,
35 | ...
36 | )
37 | }
38 | \arguments{
39 | \item{mapping}{Set of aesthetic mappings created by \code{\link[ggplot2]{aes}} or
40 | \code{\link[ggplot2]{aes_}}. If specified and \code{inherit.aes = TRUE} (the
41 | default), is combined with the default mapping at the top level of the
42 | plot. You only need to supply \code{mapping} if there isn't a mapping
43 | defined for the plot.}
44 |
45 | \item{data}{A data frame. If specified, overrides the default data frame
46 | defined at the top level of the plot.}
47 |
48 | \item{stat}{The statistical transformation to use on the data for this
49 | layer, as a string.}
50 |
51 | \item{position}{Position adjustment, either as a string, or the result of
52 | a call to a position adjustment function.}
53 |
54 | \item{parse}{If TRUE, the labels will be parsed into expressions and
55 | displayed as described in ?plotmath}
56 |
57 | \item{box.padding}{Amount of padding around bounding box, as unit or number.
58 | Defaults to 0.25. (Default unit is lines, but other units can be specified
59 | by passing \code{unit(x, "units")}).}
60 |
61 | \item{point.padding}{Amount of padding around labeled point, as unit or
62 | number. Defaults to 0. (Default unit is lines, but other units can be
63 | specified by passing \code{unit(x, "units")}).}
64 |
65 | \item{min.segment.length}{Skip drawing segments shorter than this, as unit or
66 | number. Defaults to 0.5. (Default unit is lines, but other units can be
67 | specified by passing \code{unit(x, "units")}).}
68 |
69 | \item{arrow}{specification for arrow heads, as created by \code{\link[grid]{arrow}}}
70 |
71 | \item{force}{Force of repulsion between overlapping text labels. Defaults
72 | to 1.}
73 |
74 | \item{force_pull}{Force of attraction between a text label and its
75 | corresponding data point. Defaults to 1.}
76 |
77 | \item{max.time}{Maximum number of seconds to try to resolve overlaps.
78 | Defaults to 0.5.}
79 |
80 | \item{max.iter}{Maximum number of iterations to try to resolve overlaps.
81 | Defaults to 10000.}
82 |
83 | \item{max.overlaps}{Exclude text labels when they overlap too many other
84 | things. For each text label, we count how many other text labels or other
85 | data points it overlaps, and exclude the text label if it has too many overlaps.
86 | Defaults to 10.}
87 |
88 | \item{nudge_x, nudge_y}{Horizontal and vertical adjustments to nudge the
89 | starting position of each text label. The units for \code{nudge_x} and
90 | \code{nudge_y} are the same as for the data units on the x-axis and y-axis.}
91 |
92 | \item{xlim, ylim}{Limits for the x and y axes. Text labels will be constrained
93 | to these limits. By default, text labels are constrained to the entire plot
94 | area.}
95 |
96 | \item{na.rm}{If \code{FALSE} (the default), removes missing values with
97 | a warning. If \code{TRUE} silently removes missing values.}
98 |
99 | \item{direction}{"both", "x", or "y" -- direction in which to adjust position of labels}
100 |
101 | \item{seed}{Random seed passed to \code{\link[base]{set.seed}}. Defaults to
102 | \code{NA}, which means that \code{set.seed} will not be called.}
103 |
104 | \item{verbose}{If \code{TRUE}, some diagnostics of the repel algorithm are printed}
105 |
106 | \item{show.legend}{logical. Should this layer be included in the legends?
107 | \code{NA}, the default, includes if any aesthetics are mapped.
108 | \code{FALSE} never includes, and \code{TRUE} always includes.}
109 |
110 | \item{inherit.aes}{If \code{FALSE}, overrides the default aesthetics,
111 | rather than combining with them. This is most useful for helper functions
112 | that define both data and aesthetics and shouldn't inherit behaviour from
113 | the default plot specification, e.g. \code{\link[ggplot2]{borders}}.}
114 |
115 | \item{add_points}{If \code{TRUE}, points will be added to the plot (for the
116 | labeled data only). Default size=2, color will match line color.}
117 |
118 | \item{text_aes, point_aes}{Named list, additional aesthetics to send to the
119 | text and point geoms, respectively.}
120 |
121 | \item{...}{Additional aesthetics to send to BOTH the point and text geoms.
122 | Note that if \code{add_points = FALSE}, additional parameters can be passed
123 | to the text geom here, rather than in \code{text_aes}, without breaking.}
124 | }
125 | \description{
126 | Label only the last point(s) on a plot. \code{geom_text_lastonly_repel()} can be
127 | used instead of \code{ggplot2::geom_text()} when only the last point(s)
128 | should be labeled. This is accomplished by identifying the maximum value of
129 | \code{x} in \code{data} and applying a filter to omit records where \code{x}
130 | is less than the maximum.
131 | }
132 | \details{
133 | Labels are placed by default to the right of the final point, and may be
134 | partially cut off by the plot limits. There are two known ways to address
135 | this: \enumerate{ \item Turn off panel clipping, e.g. with
136 | \code{coord_cartesian(clip = "off")}. Substitute the correct coordinate
137 | system for your plot--all have a \code{clip} argument available. Note that
138 | this will allow all geoms in the plot to draw outside the panel area, which
139 | may have unintended consequences. \item Manually expand the \code{x} scale,
140 | e.g. with \code{scale_x_continuous(expand=expand_scale(mult=0.10))} or
141 | \code{coord_cartesian(xlim = c(min, max))}. }
142 |
143 | Code was mostly copied from the source of \code{ggrepel::geom_text_repel()} and
144 | \code{ggplot2::geom_point()}.
145 | }
146 | \section{Alignment with \code{hjust} or \code{vjust}}{
147 |
148 | The arguments \code{hjust} and \code{vjust} are supported, but they only
149 | control the initial positioning, so repulsive forces may disrupt alignment.
150 | Alignment with \code{hjust} will be preserved if labels only move up and down
151 | by using \code{direction="y"}. For \code{vjust}, use \code{direction="x"}.
152 | }
153 |
154 | \examples{
155 |
156 | library(tidyverse)
157 |
158 | df <- transit_ridership \%>\%
159 | filter(system != "pace_ada") \%>\%
160 | mutate(system = recode_factor(system,
161 | cta_bus = "CTA bus",
162 | cta_rail = "CTA rail",
163 | metra = "Metra",
164 | pace = "Pace"))
165 |
166 | # Without points, label formatting or x-axis expansion
167 | ggplot(df, aes(x = year, y = ridership, color = system)) +
168 | geom_line() +
169 | labs(title = "Annual Transit Ridership") +
170 | scale_y_continuous("Ridership (Millions)") +
171 | scale_x_continuous("Year") +
172 | geom_text_lastonly()
173 |
174 |
175 | }
176 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
29 |
30 | # cmapplot
31 |
32 |
33 |
34 | [](https://github.com/CMAP-REPOS/cmapplot/actions?query=workflow%3AR-CMD-check)
36 | [](https://github.com/CMAP-REPOS/cmapplot/actions?query=workflow%3Apkgdown)
38 |
39 |
40 | This R package provides themes, color scales, and other custom functions
41 | for [ggplot2](https://github.com/tidyverse/ggplot2), based on Chicago
42 | Metropolitan Agency for Planning (CMAP) design guidelines.
43 |
44 | CMAP staff who are interested in using this package, or merely staying
45 | in the loop, are encouraged to join the [R
46 | team](https://teams.microsoft.com/l/team/19%3ad705bfd7596a4518b588ad529d2367c8%40thread.skype/conversations?groupId=d7bab529-9c30-441e-9db6-4edfdca8202c&tenantId=43b185b9-e6d9-45a5-8e36-4c08dc0ab1a2)
47 | in Microsoft Teams and follow the “cmapplot” channel.
48 |
49 | ## The basics
50 |
51 | The cmapplot package contains a few key components:
52 |
53 | 1. Apply a CMAP theme to ggplots with `theme_cmap()`
54 | 2. Easily provide common CMAP plot customizations, such as with custom
55 | geoms `geom_recessions()` and `geom_text_lastonly()`
56 | 3. Apply CMAP colors using a variety of custom functions
57 | (e.g. `cmap_fill_discrete()`)
58 | 4. Place the themed plot within a CMAP layout, and export the plot from
59 | R if desired with `finalize_plot()`
60 |
61 | ## Installation
62 |
63 | Run the following to install or update cmapplot:
64 |
65 | ``` r
66 | ## Install current version from GitHub
67 | devtools::install_github("CMAP-REPOS/cmapplot", build_vignettes=TRUE)
68 |
69 | ## Then load the package as you would any other
70 | library(cmapplot)
71 | ```
72 |
73 | For more detailed information about installing the package, particularly
74 | on a CMAP-issued computer, see [this
75 | article](https://cmap-repos.github.io/cmapplot/articles/installation.html).
76 |
77 | To install on macOS, users must install
78 | [XQuartz](https://www.xquartz.org) before cmapplot can be loaded. (This
79 | can be easily accomplished via the [Homebrew](https://brew.sh) package
80 | manager with the command `brew install --cask xquartz`.)
81 |
82 | **A note about fonts**: The cmapplot package works best when installed
83 | on a computer with the Whitney family of fonts installed (specifically
84 | the Book, Medium, and Semibold variants). If installed on a computer
85 | *without* Whitney, the package will still work, but the fonts will
86 | default to your computer’s default sans-serif font (probably Arial).
87 |
88 | ## CMAP theme and colors
89 |
90 | The function `theme_cmap()` returns a complete ggplot2 theme that can be
91 | added to a ggplot code block (similar to `ggplot2::theme_minimal()` or
92 | `ggplot2::theme_bw()`). Additionally, `theme_cmap()` accepts a variety
93 | of arguments to additionally customize the theme output. CMAP color
94 | functions apply colors from the CMAP color palette to the plot.
95 |
96 | ``` r
97 | ggplot(data = pop_and_laborforce_by_age,
98 | aes(x = value,
99 | y = interaction(year, variable, sep = " "),
100 | fill = age)) +
101 | geom_col(position = position_stack(reverse = TRUE)) +
102 | scale_x_continuous(labels = scales::percent) +
103 | theme_cmap(xlab = "Percent",
104 | gridlines = "v",
105 | vline = 0) +
106 | cmap_fill_discrete(palette = "environment")
107 | ```
108 |
109 |
110 |
111 | ## Finalizing the plot
112 |
113 | The function `finalize_plot()` places a ggplot within a frame defined by
114 | CMAP design standards. It provides a variety of customization options
115 | via arguments, and allows for in-R viewing and/or exporting in various
116 | formats.
117 |
118 | ``` r
119 | finalize_plot(title = "Regional population and labor force participation",
120 | caption = "Data from the American Community Survey",
121 | width = 7, height = 4.25)
122 | ```
123 |
124 |
125 |
126 | ## Additional reading
127 |
128 | While this package is designed to make the application of CMAP design
129 | standards to plots relatively easy, developing a professional, finished
130 | plot in R will require a decent familiarity with the grammar of
131 | [ggplot2](ggplot2.tidyverse.org/). Excellent resources in this category
132 | already exist:
133 |
134 | - The [R graphics cookbook](https://r-graphics.org/) provides
135 | accessible examples of how to make almost [any
136 | type](https://r-graphics.org/recipe-miscgraph-vectorfield) of plot,
137 | as well as how to modify things like [limits,
138 | scales](https://r-graphics.org/recipe-axes-range), [coordinate
139 | systems](https://r-graphics.org/recipe-axes-polar), and
140 | [facets](https://r-graphics.org/recipe-facet-basic).
141 | - The [ggplot2 book](https://ggplot2-book.org/) delves deeper into why
142 | and how ggplot2 works the way it does, also with distinct chapters
143 | on topics like
144 | [scales](https://ggplot2-book.org/scales-guides.html), [coordinate
145 | systems](https://ggplot2-book.org/coord.html),
146 | [facets](https://ggplot2-book.org/facet.html), etc.
147 | - The [ggplot2](ggplot2.tidyverse.org/) website.
148 | - The [R for Data Science (R4DS)](https://r4ds.had.co.nz/) book,
149 | especially the [Graphics for
150 | Communication](https://r4ds.had.co.nz/graphics-for-communication.html)
151 | chapter.
152 |
--------------------------------------------------------------------------------
/R/default_aes.R:
--------------------------------------------------------------------------------
1 | #' Initialize CMAP `default_aes` values
2 | #'
3 | #' Internal function to load in default aesthetics for modified geoms.
4 | #' Loaded in to `cmapplot_globals` in `.onLoad`.
5 | #'
6 | #' This list's names MUST equal `cmapplot_globals$geoms_that_change`
7 | #'
8 | #' @noRd
9 | init_cmap_default_aes <- function() {
10 | defaults <- list(
11 | Label = list(
12 | family = cmapplot_globals$font$strong$family,
13 | fontface = ifelse(cmapplot_globals$font$strong$face == "bold", 2, 1),
14 | size = cmapplot_globals$fsize$M / ggplot2::.pt, # pt-to-mm conversion
15 | colour = cmapplot_globals$colors$blackish
16 | ),
17 | Line = list(
18 | size = gg_lwd_convert(cmapplot_globals$consts$lwd_plotline)
19 | ),
20 | Text = list(
21 | family = cmapplot_globals$font$strong$family,
22 | fontface = ifelse(cmapplot_globals$font$strong$face == "bold", 2, 1),
23 | size = cmapplot_globals$fsize$M / ggplot2::.pt, # pt-to-mm conversion
24 | colour = cmapplot_globals$colors$blackish
25 | ),
26 | TextLast = list(
27 | family = cmapplot_globals$font$strong$family,
28 | fontface = ifelse(cmapplot_globals$font$strong$face == "bold", 2, 1),
29 | size = cmapplot_globals$fsize$M / ggplot2::.pt, # pt-to-mm conversion
30 | colour = cmapplot_globals$colors$blackish
31 | ),
32 | TextLastRepel = list(
33 | family = cmapplot_globals$font$strong$family,
34 | fontface = ifelse(cmapplot_globals$font$strong$face == "bold", 2, 1),
35 | size = cmapplot_globals$fsize$M / ggplot2::.pt, # pt-to-mm conversion
36 | colour = cmapplot_globals$colors$blackish
37 | ),
38 | PointLast = list(
39 | size = 2 * gg_lwd_convert(cmapplot_globals$consts$lwd_plotline)
40 | ),
41 | RecessionsText = list(
42 | family = cmapplot_globals$font$regular$family,
43 | fontface = ifelse(cmapplot_globals$font$regular$face == "bold", 2, 1),
44 | size = cmapplot_globals$fsize$S / ggplot2::.pt, # pt-to-mm conversion
45 | colour = cmapplot_globals$colors$blackish
46 | ),
47 | PandemicsText = list(
48 | family = cmapplot_globals$font$regular$family,
49 | fontface = ifelse(cmapplot_globals$font$regular$face == "bold", 2, 1),
50 | size = cmapplot_globals$fsize$S / ggplot2::.pt, # pt-to-mm conversion
51 | colour = cmapplot_globals$colors$blackish
52 | )
53 | )
54 |
55 | # Return this list only if it lines up with `geoms_that_change`.
56 | # Otherwise, throw an error.
57 | if (setequal(names(defaults), cmapplot_globals$geoms_that_change)) {
58 | return(defaults)
59 | } else {
60 | stop(
61 | "DEV ISSUE: programmed list of `default_aes` does not line up with
62 | `cmapplot_globals$geoms_that_change`.",
63 | call. = FALSE
64 | )
65 | }
66 | }
67 |
68 | #' Fetch and set aesthetic defaults
69 | #'
70 | #' These functions allow for setting and resetting default aesthetic values for
71 | #' certain ggplot2 geoms. This is necessary for geoms to be "themed" to CMAP
72 | #' style standards, because (at least at the moment) setting geom aesthetic
73 | #' defaults on a plot-by-plot basis (such as with \code{ggplot2::theme}) is not
74 | #' possible. The geoms impacted are stored in
75 | #' \code{cmapplot_globals$geoms_that_change}.
76 | #'
77 | #' These functions are employed implicitly within \code{\link{finalize_plot}} to
78 | #' apply preferred aesthetic defaults to final outputs. They are only necessary
79 | #' to use explicitly if you would like plots to use these defaults
80 | #' pre-\code{finalize}.
81 | #'
82 | #' CAUTION: Running \code{apply_cmap_default_aes} will set defaults for all
83 | #' ggplot2 plots drawn in the current session. To reset to \code{ggplot2}
84 | #' defaults (technically, to whatever the defaults were when \code{cmapplot}
85 | #' was loaded), use \code{unapply_cmap_default_aes}.
86 | #'
87 | #' Note: CMAP aesthetic defaults are loaded into
88 | #' \code{cmapplot_globals$default_aes_cmap} by the internal pkg function
89 | #' \code{init_cmap_default_aes} when \code{cmapplot} is first loaded into R.
90 | #'
91 | #' @param quietly Should the function suppress confirmation message?
92 | #'
93 | #' @examples
94 | #' \dontrun{
95 | #' g <- ggplot(filter(grp_over_time, category == "Services"),
96 | #' aes(x = year, y = realgrp, color = cluster)) +
97 | #' geom_recessions(ymax = 0.4, text_nudge_x = 0.1) +
98 | #' theme_cmap(hline = 0,
99 | #' axislines = "x",
100 | #' legend.max.columns = 2) +
101 | #' ggtitle("Change in gross regional product over time") +
102 | #' geom_line() +
103 | #' scale_x_continuous("Year", breaks = seq(2007, 2017, 2)) +
104 | #' coord_cartesian(clip = "off") +
105 | #' geom_text_lastonly(aes(label = realgrp), add_points = TRUE)
106 | #'
107 | #' # print normally
108 | #' g
109 | #'
110 | #' # overwrite `default_aes`
111 | #' apply_cmap_default_aes()
112 | #' g
113 | #'
114 | #' # reset `default_aes`
115 | #' unapply_cmap_default_aes()
116 | #' g
117 | #'
118 | #' # finalize alters the defaults implicitly, but then resets them automatically.
119 | #' finalize_plot(g)
120 | #'
121 | #' # you can also use `finalize` without these modifications
122 | #' finalize_plot(g, use_cmap_aes = FALSE)
123 | #' }
124 | #'
125 | #' @name cmap_default_aes
126 | NULL
127 |
128 | #' @describeIn cmap_default_aes Apply CMAP aesthetic defaults to all ggplots in
129 | #' the current session
130 | #'
131 | #' @export
132 | apply_cmap_default_aes <- function(quietly = FALSE) {
133 | set_default_aes(cmapplot_globals$default_aes_cmap)
134 |
135 | if (!quietly) {
136 | message(
137 | paste0(
138 | "Aesthetic defaults overridden in the current session for the following Geoms:",
139 | "\n ",
140 | paste(cmapplot_globals$geoms_that_change, collapse = ", "),
141 | "\nTo undo this change, run `unapply_cmap_default_aes()`."
142 | )
143 | )
144 | }
145 | }
146 |
147 |
148 | #' @describeIn cmap_default_aes Reset modified geom aesthetics to their values
149 | #' when \code{cmapplot} was first loaded
150 | #'
151 | #' @export
152 | unapply_cmap_default_aes <- function(quietly = FALSE) {
153 | set_default_aes(cmapplot_globals$default_aes_cached)
154 |
155 | if (!quietly) {
156 | message(
157 | paste0(
158 | "Aesthetic defaults reset to values cached when pkg `cmapplot` was first loaded for Geoms:",
159 | "\n ",
160 | paste(cmapplot_globals$geoms_that_change, collapse = ", ")
161 | )
162 | )
163 | }
164 | }
165 |
166 |
167 | #' Fetch `default_aes` from select geoms
168 | #'
169 | #' Internal function to fetch `default_aes` for geoms that this package plans to
170 | #' overwrite. Used in `.onLoad` and in `finalize_plot`.
171 | #'
172 | #' @importFrom purrr map
173 | #' @noRd
174 | fetch_current_default_aes <- function() {
175 | purrr::map(
176 | cmapplot_globals$geoms_that_change,
177 | function(geom) {
178 | get(paste0("Geom", geom))$default_aes
179 | }
180 | ) %>%
181 | rlang::set_names(cmapplot_globals$geoms_that_change)
182 | }
183 |
184 |
185 | #' Set `default_aes` for select geoms
186 | #'
187 | #' Internal function to overwrite `default_aes` for the necessary geoms. Used in
188 | #' `finalize_plot`, `apply_cmap_geom_defaults` and `unapply_cmap_geom_defaults`.
189 | #'
190 | #' @param values A named list of parameters, presumably from (or at least a
191 | #' parallel structure to) the output of `fetch_cmap_geom_defaults`.
192 | #'
193 | #' @importFrom purrr walk2
194 | #' @noRd
195 | set_default_aes <- function(values) {
196 | purrr::walk2(
197 | cmapplot_globals$geoms_that_change,
198 | values,
199 | ggplot2::update_geom_defaults
200 | )
201 | }
202 |
--------------------------------------------------------------------------------
/NEWS.md:
--------------------------------------------------------------------------------
1 | # cmapplot 1.2.1
2 | PR #143
3 |
4 | ### Bug fixes
5 | * `cmap_fill_race` and `cmap_color_race` have been updated to remove unused race/ethnicity categories from chart legend (see issue #142)
6 |
7 |
8 | # cmapplot 1.2.0
9 | PR #123
10 |
11 | This is a version-level update that includes many fixes and new features and introduces new dependencies, most significantly RStudio 1.4 or greater.
12 |
13 | ### New features
14 | * cmapplot now utilizes the new systemfonts package for custom font rendering, rather than sysfonts on Windows and X11fonts on Mac and other Unix-based machines. In addition, raster exports from `finalize_plot` now rely on the new raster drawing package ragg. These changes improve font accuracy and consistency across platforms. Note that this improvement does not yet extend to svg outputs, but may in the future (#134).
15 | * When an axis breaks are 4-digit years, new function `abbr_years` allows the conversion of specific years to 2-digit abbreviations, as is common on some designed CMAP graphics.
16 | * `cmapplot_globals`, which contains key package constants, is now an internal environment rather than an exported list. It can be accessed via new functions `get_cmapplot_globals` and `get_cmapplot_global`. Constants can now be overridden by the user for the current session by using `set_cmapplot_global`. Note that this does not yet apply to geom aesthetics set by the package, but may in the future (issue #117).
17 | * All palettes programmed into the package have been moved into a tibble at `cmapplot_globals$palettes`. A new function `fetch_pal` can be used to get details about any specific palette.
18 |
19 | ### Bug fixes
20 | * Continuous color gradients can now be used on discrete color scales. E.g. `cmap_color_discrete` and `cmap_fill_discrete` can now call gradients as well as discrete palettes (see #70 and #119)
21 | * Nomenclature in help files (e.g. "palette" vs "scale") has been adjusted for clarity.
22 | * internal table `recessions` has been updated to include the business cycle contraction that began in Feb 202 (no end date for this cycle yet).
23 | * `geom_recessions` and related `update_recessions` have been updated to allow for ongoing recessions, improve NBER source for recessions table, and decrease likelihood of data fetch errors.
24 |
25 | ### Backend changes
26 | * pkgdown site now correctly displays Whitney fonts and margin description images
27 | * backend script reorganization
28 | * improvements to pkgdown build github action, including ability to publish a test site
29 |
30 | ### Backward compatibility notes
31 | * **This package will now only render Whitney Fonts in RStudio when RStudio version >= 1.4**
32 | * `finalize_plot`'s `window` mode has been disabled for now, due to inability to use ragg drivers in independent window devices. Use `mode = "plot"` and click the "Zoom" button in the plot window instead.
33 | * `cmapplot_globals`, the exported list of package constants, has been removed (See new features `set_cmapplot_global` etc)
34 | * Color lists `cmap_palettes` and `cmap_gradients` have been removed (This information has been moved to `cmapplot_globals$palettes`. To access palette colors directly, use, say `fetch_pal("reds")` rather than `cmap_gradients$reds`.
35 | * `viz_palette` and `viz_gradient` now take as a first argument either the name of a palette (e.g. `"reds"`) or the color palette itself (e.g. `fetch_pal("reds")`). `viz_palette(cmap_gradient$reds)` no longer works.
36 | * `integer_breaks` removed from package
37 |
38 |
39 | # cmapplot 1.1.0
40 | PR #111 | February 24, 2021
41 |
42 | PR #115 | March 2, 2021
43 |
44 | This pair of updates primarily makes many changes to `finalize_plot()` to enable printing plots without the left-hand "sidebar" -- the area that contains the title and the caption. Most but not all changes are under the hood and should not impact the user. Those that will impact the user include:
45 |
46 | * There is a new argument, `inherit`, that allows the user to specify whether cmapplot should attempt to inherit titles and/or captions from the underlying ggplot object.
47 | * The argument `title_width` has been renamed `sidebar_width` to better reflect its function.
48 | * Setting `sidebar_width = 0` now has the effect of shifting the title above the topline and shifting the caption from the title column to directly below the plot. If the user does not want a title on the vertical layout graphic, this can be achieved by leaving `title = ""`, the default, and (if relevant) specifying that `finalize_plot()` should not attempt to inherit a title from the underlying ggplot object.
49 | * There is a new argument, `caption_align`, which takes numeric range 0 to 1. `0`, the default, aligns the caption bottom or left (in title-column and below-plot captions, respectively). `1` aligns the caption top or right. `0.5` centers. The argument `caption_valign` has been deprecated.
50 | * The value `margin_title_l` has been replaced with `margin_sidebar_l`, which only affects horizontal layout graphics. The margin for titles and captions in the vertical layout is based on `margin_plot_l`.
51 | * Separately, this version also creates this `NEWS.md` file for the pkgdown website.
52 |
53 | Under-the-hood changes to `finalize_plot()` are documented in PR #111, specifically [here](https://github.com/CMAP-REPOS/cmapplot/pull/111#issuecomment-782779446).
54 |
55 | ### Backward compatibility notes
56 | Users who have written code with previous versions of cmapplot should note these known compatibility issues:
57 | * In `finalize_plot()`, the argument `caption_valign` has been deprecated and will now issue a message alert (but will still work, for now). Please update your code to use the new argument `caption_align`.
58 | * In `finalize_plot()`, the argument `title_width` has been deprecated and will now issue a message alert (but will still work, for now). Please update your code to use the new argument `sidebar_width`.
59 | * Any overrides using the deprecated value `margin_title_l` will no longer have any affect. Use `margin_sidebar_l` instead.
60 |
61 |
62 | # cmapplot 1.0.4
63 | PR #110 | February 3, 2021
64 |
65 | * The ggplot2 geom `geom_label` is now added to the list of geoms for which text aesthetics are automatically updated to CMAP style (ie to Whitney fonts). Previously, only `geom_text` and the custom `geom_text_last` were available in CMAP style.
66 |
67 |
68 | # cmapplot 1.0.3
69 | PR #107 | February 2, 2021
70 |
71 | * Modified `finalize_plot()` to accept `title_width = 0` without causing a fuss. This is a short-term fix, with more improvements coming.
72 | * In `cmapplot_globals$consts`, eliminated `margin_title_r`, which created space between the title/caption and plotbox inside the title column. Replaced it with `margin_plot_l`, which creates the same buffer but does so in the plot column, not the title column. This was necessary to keep an active left-hand margin in situations where `title_width = 0`.
73 |
74 | ### Backward compatibility notes
75 | Users who have written code with previous versions of cmapplot should note these known compatibility issues:
76 | * `margin_title_r` no longer exists. Code that overrides this in `finalize_plot()` should not error, but will also have no effect on your plot. Change to `margin_plot_l`.
77 | * Titles and captions will be a bit wider (the width of the title and caption grobs are no longer modified by `margin_title_r`).
78 | * Plots will be a bit narrower (the width of the plotbox is now modified by `margin_plot_l`).
79 |
80 |
81 | # cmapplot 1.0.2
82 | PR #103 | January 11, 2021
83 |
84 | * Fixed bug where custom color functions (e.g. `cmap_fill_continuous()` etc) did not allow for passing other arguments on to ggplot2's `scale` functions (see issue #102).
85 |
86 |
87 | # cmapplot 1.0.1
88 | PR #100 | December 9, 2020
89 |
90 | * Improvement of tickmark handling via addition of `axisticks` argument in `theme_cmap()` and new `length_ticks` default value in `cmapplot_globals$consts`.
91 | * Substantial backend simplification of how `theme_cmap()` generates theme objects (not of substantial significance to users).
92 |
93 |
94 | # cmapplot 1.0.0
95 | December 1, 2020
96 |
97 | * Initial package release.
98 |
--------------------------------------------------------------------------------
/R/data.R:
--------------------------------------------------------------------------------
1 | #' Job change in CMAP region by cluster, 2001-17
2 | #'
3 | #' A test dataset containing 2001-17 job change and other data for the 22 specialized traded clusters
4 | #' analyzed in the CMAP Traded Clusters report.
5 | #'
6 | #' @format A tibble. 22 rows and 5 variables:
7 | #' \describe{
8 | #' \item{code}{Integer. code of cluster}
9 | #' \item{name}{Char. textual description/cluster title}
10 | #' \item{category}{Factor. Either "goods-producing" or "services"}
11 | #' \item{assessment}{Factor. "Leading", "Mixed", or "Trailing"}
12 | #' \item{jobchange}{Integer. Total change in employment in the cluster between 2001-17}
13 | #' }
14 | #' @source CMAP traded clusters report
15 | #'
16 | #' @examples
17 | #' # A bar chart
18 | #' ggplot(cluster_jobchange, aes(x = reorder(name, jobchange), y = jobchange, fill = category)) +
19 | #' geom_col() +
20 | #' coord_flip()
21 | #'
22 | #'
23 | "cluster_jobchange"
24 |
25 |
26 | #' Basic regional economic stats in 2001 and 2017
27 | #'
28 | #' A test dataset containing count of jobs, earnings, and establishments in the Chicago region in both 2001 and 2017.
29 | #'
30 | #' @format A tibble. 18 rows and 4 variables:
31 | #' \describe{
32 | #' \item{variable}{Chr. Indicates the meaning of the data stored in `value`. Jobs, Real Earnings, or Establishments.}
33 | #' \item{year}{Factor. 2001 or 2017.}
34 | #' \item{sector}{Chr. local, tradedgoods, or tradedservices. Together, these three sectors account for all clusters in the region.}
35 | #' \item{value}{Int. The value indicated as described by the other columns}
36 | #' }
37 | #' @source CMAP traded clusters report
38 | #'
39 | #' @examples
40 | #' # a grouped and stacked bar chart (via `interaction()`)
41 | #' ggplot(economy_basic, aes(x = interaction(year, variable), y = value, fill = sector)) +
42 | #' geom_col(position = "fill") +
43 | #' scale_y_continuous(labels = scales::percent)
44 | #'
45 | "economy_basic"
46 |
47 |
48 | #' Gross Regional Product by cluster, 2007-17
49 | #'
50 | #' A test dataset containing real GRP data for the CMAP region.
51 | #'
52 | #' @format A tibble. 121 rows and 5 variables:
53 | #' \describe{
54 | #' \item{cluster}{Chr. The name of the cluster}
55 | #' \item{category}{Factor. "goods-producing" or "services"}
56 | #' \item{assessment}{Factor. "Trailing", "Mixed", or "Leading"}
57 | #' \item{year}{Double. The year of the data}
58 | #' \item{realgrp}{Double. The real gross regional product of the cluster in year `year`.
59 | #' Not exactly sure on the inflation year but I believe it is 2012}
60 | #' }
61 | #' @source CMAP traded clusters report
62 | #'
63 | #' @examples
64 | #' # a time-series line chart
65 | #' ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
66 | #' geom_line()
67 | #'
68 | "grp_over_time"
69 |
70 |
71 | #' Gross Regional Product by region, with peers, 2001-17
72 | #'
73 | #' A test dataset containing real GRP data for the CMAP and peer regions.
74 | #'
75 | #' @format A tibble. 121 rows and 5 variables:
76 | #' \describe{
77 | #' \item{area}{Factor. name of the region}
78 | #' \item{year}{Double. year of the data}
79 | #' \item{grp}{Double. real gross regional product}
80 | #' }
81 | #' @source CMAP traded clusters report
82 | #'
83 | #' @examples
84 | #' # a time-series line chart
85 | #' ggplot(grp_over_time, aes(x = year, y = realgrp, color = cluster)) +
86 | #' geom_line()
87 | #'
88 | "peer_grp"
89 |
90 |
91 | #' Wage percentiles by cluster
92 | #'
93 | #' A test dataset containing the 10th, 25th, 50th, 75th, and 90th percentile wage by cluster in the CMAP region.
94 | #'
95 | #' @format A tibble. 45 rows and 3 variables:
96 | #' \describe{
97 | #' \item{cluster}{Chr. The name of the cluster}
98 | #' \item{percentile}{Double. The percentile wage being reported}
99 | #' \item{wage}{Double. The wage. I believe 2017 data.}
100 | #' }
101 | #' @source CMAP traded clusters report
102 | #'
103 | #' @examples
104 | #' # a non-time-series line chart
105 | #' ggplot(percentile_wages, aes(x = percentile, y = wage, color = cluster)) +
106 | #' geom_line()
107 | #'
108 | "percentile_wages"
109 |
110 |
111 | #' Population and Labor Force by Age
112 | #'
113 | #' A test dataset containing percentage breakdowns of the population and labor force by various age buckets in 2010 and 2017.
114 | #'
115 | #' @format A tibble. 12 rows and 4 variables:
116 | #' \describe{
117 | #' \item{variable}{Chr. Indicates the meaning of the data stored in `value`. "population" or "laborforce".}
118 | #' \item{year}{Factor. 2010 or 2017.}
119 | #' \item{age}{Chr. The age bucket. Either 16-24, 25-54, or 55+.}
120 | #' \item{value}{Double. The value indicated by the other variables.}
121 | #' }
122 | #' @source CMAP traded clusters report
123 | #'
124 | #' @examples
125 | #' # a grouped and stacked bar chart (via `interaction()`)
126 | #' ggplot(pop_and_laborforce_by_age, aes(x = interaction(year, variable), y = value, fill = age)) +
127 | #' geom_col(position = position_stack(reverse = TRUE))
128 | #'
129 | "pop_and_laborforce_by_age"
130 |
131 |
132 | #' Traded employment by race
133 | #'
134 | #' A test dataset containing the percentage breakdowns of the working population employed in traded clusters, by race.
135 | #'
136 | #'
137 | #' @format A tibble. 12 rows and 4 variables:
138 | #' \describe{
139 | #' \item{Race}{Chr. White, Asian, Hispanic, Other, Black, or Regional Average.}
140 | #' \item{variable}{Chr. SpecializedTraded, UnspecializedTraded, or Total.
141 | #' Total is a sum of SpecializedTraded and UnspecializedTraded. The invisible remainder (e.g. `1-Total` or
142 | #' `1-(SpecializedTraded+UnspecializedTraded)`) is the percentage employed in local clusters.}
143 | #' \item{value}{Double. The value indicated by the other variables.}
144 | #' }
145 | #' @source CMAP traded clusters report
146 | #'
147 | #' @examples
148 | #' # a stacked bar chart
149 | #' \dontshow{library(dplyr)}
150 | #' df <- dplyr::filter(
151 | #' traded_emp_by_race,
152 | #' variable %in% c("SpecializedTraded", "UnspecializedTraded")
153 | #' )
154 | #' ggplot(df, aes(x = reorder(Race, -value), y = value, fill = variable)) +
155 | #' geom_col(position = position_stack(reverse = TRUE)) +
156 | #' scale_y_continuous(labels = scales::percent)
157 | #'
158 | "traded_emp_by_race"
159 |
160 |
161 |
162 | #' Transit ridership in the Chicago region, 1980-2024
163 | #'
164 | #' A test dataset containing 1980-2019 transit ridership for the three service
165 | #' boards that provide transit in Northeastern Illinois.
166 | #'
167 | #' @format A tibble. 225 rows and 3 variables
168 | #' \describe{
169 | #' \item{year}{Double. Year of data}
170 | #' \item{system}{Char. Name of system (includes CTA bus, CTA rail, Metra, Pace, and Pace ADA)}
171 | #' \item{ridership}{Double. Annual unlinked passenger trips in millions}
172 | #' }
173 | #' @source Regional Transportation Authority \url{http://www.rtams.org/rtams/systemRidership.jsp}
174 | #'
175 | #' @examples
176 | #' # A line graph
177 | #' ggplot(transit_ridership,aes(x = year,y=ridership,group=system,color=system)) +
178 | #' geom_line(na.rm=TRUE)
179 | #'
180 | #'
181 | "transit_ridership"
182 |
183 |
184 |
185 |
186 | #' Vehicle ownership in the CMAP seven county region
187 | #'
188 | #' A test dataset containing vehicle ownership rates in the seven county region
189 | #' of northeastern Illinois.
190 | #'
191 | #' @format A tibble. 40 rows and 3 variables
192 | #' \describe{
193 | #' \item{county}{Char. Name of county}
194 | #' \item{number_of_veh}{Char. Number of vehicles owned by household}
195 | #' \item{pct}{Numeric. Share of households with the given number of vehicles (values between 0 and 1)}
196 | #' }
197 | #' @source CMAP Travel Inventory Survey Data Summary \url{https://www.cmap.illinois.gov/documents/10180/77659/Travel+Inventory+Survey+Data+Summary_weighted_V2.pdf/d4b33cdd-1c44-4322-b32f-2f54b85207cb}
198 | #'
199 | #' @examples
200 | #' # A stacked bar chart
201 | #' ggplot(vehicle_ownership,
202 | #' aes(x = county, y = pct, fill = number_of_veh)) +
203 | #' geom_bar(position = position_stack(), stat = "identity")
204 | #'
205 | "vehicle_ownership"
206 |
207 |
--------------------------------------------------------------------------------
/vignettes/colors.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Applying CMAP color schemes"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{Applying CMAP color schemes}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r setup, include = FALSE}
11 | knitr::opts_chunk$set(
12 | collapse = TRUE,
13 | comment = "#>",
14 | fig.width = 7,
15 | fig.asp = 400/670,
16 | fig.retina = 4,
17 | fig.align = "center",
18 | dev = "ragg_png"
19 | )
20 |
21 | library(tidyverse)
22 | library(cmapplot)
23 | ```
24 |
25 | There are `r nrow(get_cmapplot_global("palettes"))` color palettes in the cmapplot package, across three categories: discrete, sequential, and divergent. Mirroring the underlying functionality of ggplot2, cmapplot can apply these color palettes as either `discrete` or `continuous` scales to either the `color` (outline) or `fill` attributes of a ggplot.
26 |
27 | This table lists all palettes currently available in the package:
28 |
29 | ```{r palettes, echo = FALSE, results = 'asis'}
30 |
31 | pals <- get_cmapplot_global("palettes")
32 | discrete <- filter(pals, type == "discrete")[["name"]]
33 | sequential1 <- filter(pals, type == "sequential", !stringr::str_detect(name, "_"))[["name"]]
34 | sequential2 <- filter(pals, type == "sequential", stringr::str_detect(name, "_"))[["name"]]
35 | divergent <- filter(pals, type == "divergent")[["name"]]
36 |
37 | maxlength <- max(length(discrete), length(sequential1), length(sequential2), length(divergent))
38 | length(discrete) <- length(sequential1) <- length(sequential2) <- length(divergent) <- maxlength
39 |
40 | out <- tibble(Discrete = discrete,
41 | Sequential = sequential1,
42 | `Sequential (multi-hue)` = sequential2,
43 | Divergent = divergent)
44 | out[is.na(out)] <- ""
45 |
46 | knitr::kable(out)
47 | ```
48 |
49 | ## Using CMAP color palettes in plots
50 |
51 | ### Discrete scales
52 |
53 | Discrete color scales are used to assign colors to discrete bins, such as the lines in a time series line chart. Discrete scale functions work with any palette -- discrete, sequential, or divergent. Add a discrete color scale by calling either the `cmap_fill_discrete()` or `cmap_color_discrete()` function in your plot construction.
54 |
55 | Note that discrete scales will automatically interpolate additional colors if the dataset has more colors than the underlying palette. This can be helpful but is not ideal for finished graphics.
56 |
57 | ```{r color_discrete, message = FALSE}
58 | df <- dplyr::filter(grp_over_time, category == "Goods-Producing")
59 |
60 | ggplot(data = df) +
61 | geom_line(mapping = aes(x = year, y = realgrp, color = cluster),
62 | size = 1.25) +
63 | scale_x_continuous(breaks = seq(from = 2007, to = 2017, by = 2)) +
64 | cmap_color_discrete(palette = "community", reverse = TRUE) +
65 | theme_cmap() +
66 | ggtitle("Real GRP of goods-producing clusters over time")
67 | ```
68 |
69 | ### Race/ethnicity scale
70 |
71 | In order to maintain a consistent data language, CMAP uses specific colors for displaying data based on race and ethnicity. To map these colors to each demographic group, use `cmap_fill_race()` or `cmap_color_race()`.
72 |
73 | In the arguments, specify the case-sensitive name of each group as it appears in your data. The functions can be used even if your dataset does not contain every race/ethnicity category — simply omit the parameters for the missing categories. Likewise, if your dataset already contains the default race/ethnicity categories (case-sensitive) specified in the race palette, no arguments have to be provided.
74 |
75 | ```{r color_race, message = FALSE}
76 | df <- dplyr::filter(
77 | traded_emp_by_race,
78 | Race != "Regional average" & variable == "SpecializedTraded"
79 | )
80 |
81 | ggplot(data = df) +
82 | geom_col(mapping = aes(x = Race, y = value, fill = Race)) +
83 | scale_y_continuous(labels = scales::label_percent(accuracy = 1)) +
84 | cmap_fill_race(white = "White",
85 | black = "Black",
86 | hispanic = "Hispanic",
87 | asian = "Asian",
88 | other = "Other") +
89 | theme_cmap(show.legend = FALSE) + # Legend is redundant in this example
90 | ggtitle("Percent employed in specialized traded clusters, by race")
91 | ```
92 |
93 | ### Continuous scales
94 | Continuous color scales work with sequential and divergent palettes. Add a continuous scale by calling either the `cmap_fill_continuous()` or `cmap_color_continuous()` function in your plot construction. If you're using a divergent palette, you can specify the midpoint where the divergence begins (default is zero).
95 |
96 | ```{r color_continuous, message = FALSE}
97 | df <- dplyr::filter(
98 | percentile_wages,
99 | cluster %in% c("Biopharmaceuticals", "Hospitality and Tourism", "Paper and Packaging")
100 | )
101 |
102 | ggplot(data = df) +
103 | geom_point(mapping = aes(x = cluster, y = wage, color = percentile),
104 | size = 5) +
105 | scale_y_continuous(labels = scales::dollar) +
106 | scale_x_discrete(labels = scales::label_wrap(18)) +
107 | coord_flip() +
108 | cmap_color_continuous(palette = "red_teal", middle = 50) +
109 | theme_cmap() +
110 | ggtitle("Wage percentiles for key clusters")
111 | ```
112 |
113 | ### Highlighting categories
114 |
115 | If you want to draw attention to a specific group in your graph, use `cmap_fill_highlight()` or `cmap_color_highlight()`. This will make your highlighted group one color and all other groups identical in another color. Specify the vector in your data that determines the groups, and then the value of the group to be singled out. Note that this *must* be the same vector specified in the `fill`/`color` aesthetic. The highlight and non-highlight colors have defaults, but can be changed with the `color_value` and `color_other` parameters, respectively.
116 |
117 | More than one category can be highlighted as well, by feeding a vector of values into the the `value` argument. See `?cmap_fill_highlight` for details.
118 |
119 | ```{r color_highlight, message = FALSE}
120 | df <- dplyr::filter(transit_ridership, year == 2019)
121 |
122 | ggplot(data = df) +
123 | geom_col(mapping = aes(x = system, y = ridership, fill = system)) +
124 | cmap_fill_highlight(field = transit_ridership$system,
125 | value = "metra") +
126 | theme_cmap(show.legend = FALSE) + # Legend is redundant in this example
127 | ggtitle("Annual passenger trips by service, in millions")
128 | ```
129 |
130 |
131 | ## Available color palettes
132 | Palettes are stored in a tibble in the `cmapplot_globals` environment. This tibble can be accessed with `get_cmapplot_global("palettes")`, with specific details about any specific palette most easily accessed with `fetch_pal()`. Palettes can be visualized in the plot window with `viz_palette()` and `viz_gradient()`.
133 |
134 | ### Discrete palettes
135 | Use these palettes with `cmap_fill_discrete()` or `cmap_color_discrete()`:
136 | ```{r show_discrete, echo = FALSE, fig.asp = 300/670}
137 | nms <- dplyr::filter(get_cmapplot_global("palettes"), type == "discrete", name != "race")$name
138 | purrr::walk(nms, viz_palette)
139 | ```
140 |
141 | The race palette is a special discrete palette, which should be used with the specific functions `cmap_fill_race()` or `cmap_color_race()`:
142 | ```{r show_discrete_palettes, echo = FALSE, fig.asp = 300/670}
143 | viz_palette("race")
144 | ```
145 |
146 | ### Sequential palettes
147 | Use these palettes with `cmap_fill_continuous()`/`cmap_color_continuous()` or `cmap_fill_discrete()`/`cmap_color_discrete()`.
148 | ```{r show_sequential, echo = FALSE, fig.asp = 300/670}
149 | nms <- dplyr::filter(get_cmapplot_global("palettes"), type == "sequential")$name
150 | purrr::walk(nms, viz_gradient)
151 | ```
152 |
153 | If you use a sequential palette for a discrete scale, the package will automatically choose colors from across the selected gradient and interpolate additional ones if needed. For example, the `blues` palette is shown below, interpolating nine colors from the initial palette list of seven.
154 |
155 | ```{r show_sequential_discrete, echo = FALSE, fig.asp = 300/670}
156 | viz_palette("blues", num = 9)
157 | ```
158 |
159 | ### Divergent palettes
160 | Use these palettes with `cmap_fill_continuous()`/`cmap_color_continuous()` or `cmap_fill_discrete()`/`cmap_color_discrete()`. Using these palettes for a discrete scale will behave similarly to the discrete use of `blues` shown above.
161 | ```{r show_diverent, echo = FALSE, fig.asp = 300/670}
162 | nms <- dplyr::filter(get_cmapplot_global("palettes"), type == "divergent")$name
163 | purrr::walk(nms, viz_gradient)
164 | ```
165 |
166 |
--------------------------------------------------------------------------------
/R/utilities.R:
--------------------------------------------------------------------------------
1 | #' Font visualization test
2 | #'
3 | #' This internal function uses base R graphics to display the five text variants
4 | #' that should show up on a CMAP themed graphic - and what fonts the package is
5 | #' planning to use to display them.
6 | #'
7 | #' @noRd
8 | display_cmap_fonts <- function() {
9 | graphics::plot(c(0,2), c(0,6), type="n", xlab="", ylab="")
10 |
11 | draw.me <- function(name, font, size, placement){
12 | thisfont <- cmapplot_globals$font[[font]]
13 | thissize <- cmapplot_globals$fsize[[size]]
14 |
15 | graphics::par(family=thisfont$family,
16 | font=ifelse(thisfont$face == "bold", 2, 1))
17 | graphics::text(1, placement,
18 | paste(name,
19 | paste(paste("font:", font), paste("size:", size), sep = ", "),
20 | paste(thisfont$family, thisfont$face, thissize, sep = ", "),
21 | sep = " | "),
22 | cex=thissize/12, ps=12)
23 | }
24 |
25 | draw.me(name = "Title", font = "strong", size = "L", 5)
26 | draw.me(name = "Main", font = "regular", size = "M", 4)
27 | draw.me(name = "Axis", font = "light", size = "M", 3)
28 | draw.me(name = "Label", font = "strong", size = "M", 2)
29 | draw.me(name = "Note", font = "light", size = "S", 1)
30 | }
31 |
32 |
33 |
34 | # Plot sizes and colors ---------------------------------------------------
35 |
36 | #' Line width conversion
37 | #'
38 | #' The factor \code{.lwd} is used to calculate correct output sizes for line
39 | #' widths. For line widths in \code{ggplot2}, the size in mm must be divided
40 | #' by this factor for correct output. Because the user is likely to prefer
41 | #' other units besides for mm, \code{gg_lwd_convert()} is provided as a
42 | #' convenience function, converting from any unit all the way to ggplot units.
43 | #'
44 | #' \code{.lwd} is equal to \code{ggplot2::.stroke / ggplot2::.pt}. In
45 | #' \code{ggplot2}, the size in mm is divided by \code{.lwd} to achieve the
46 | #' correct output. In the \code{grid} package, however, the size in points
47 | #' (\code{pts} (or maybe \code{bigpts}? Unclear.) must be divided by
48 | #' \code{.lwd}. The user is unlikely to interact directly with \code{grid},
49 | #' but this is how \code{finalize_plot()} does its work.
50 | #'
51 | #' This is closely related to \code{ggplot::.pt}, which is the factor that
52 | #' font sizes (in \code{pts}) must be divided by for text geoms within
53 | #' \code{ggplot2}. Confusingly, \code{.pt} is not required for \code{ggplot2}
54 | #' font sizes outside the plot area: e.g. axis titles, etc.
55 | #'
56 | #' @seealso grid's \code{\link[grid]{unit}}, ggplot2's
57 | #' \code{\link[ggplot2]{.pt}}, and
58 | #' \url{https://stackoverflow.com/questions/17311917/ggplot2-the-unit-of-size}
59 | #'
60 | #' @examples
61 | #' ggplot() + coord_cartesian(xlim = c(-3, 3), ylim = c(-3, 3)) +
62 | #'
63 | #' # a green line 3 points wide
64 | #' geom_hline(yintercept = 1, color = "green", size = gg_lwd_convert(3)) +
65 | #'
66 | #' # black text of size 24 points
67 | #' annotate("text", -2, 0, label = "text", size = 24/ggplot2::.pt)
68 | #'
69 | #'
70 | #' # a blue line 6 points wide, drawn over the plot with the `grid` package
71 | #' grid::grid.lines(y = 0.4, gp = grid::gpar(col = "blue", lwd = 6 / .lwd))
72 | #'
73 | #' @export
74 | .lwd <- ggplot2::.pt / ggplot2::.stroke
75 |
76 |
77 | #' Helper function to calculate correct size for ggplot line widths.
78 | #'
79 | #' @param value Numeric, the value to be converted.
80 | #' @param unit Char, the unit of the value to be converted. Can be any of the
81 | #' units accepted by \code{grid::unit()}, including "bigpts", "pt", "mm", and
82 | #' "in". Default is \code{bigpts}.
83 | #'
84 | #' @describeIn dot-lwd Function to convert from any unit directly to ggplot2's
85 | #' preferred millimeters.
86 | #'
87 | #' @export
88 | gg_lwd_convert <- function(value, unit = "bigpts") {
89 |
90 | # convert input type to mm
91 | value_out <- grid::convertUnit(grid::unit(value, unit), "mm", valueOnly = TRUE)
92 |
93 | # return with conversion factor
94 | return(
95 | value_out / .lwd
96 | )
97 | }
98 |
99 |
100 |
101 | #' Identify correct font path based on filename
102 | #'
103 | #' Taking a list of font paths, search for a specific filename. If a perfect
104 | #' match is found, return that path.
105 | #'
106 | #' @param filename the complete file name, less a .otf or .ttf extension.
107 | #' @param path a vector of filepaths
108 | #'
109 | #' @noRd
110 | find_path <- function(filename, paths){
111 | result <- grep(paste0("(\\\\|/)", filename, ".[ot]tf$"), paths, value = TRUE)
112 |
113 | if(length(result) >= 1){
114 | return(result[1])
115 | } else {
116 | stop(
117 | paste0("Font '", filename, "' not found."),
118 | call. = FALSE)
119 | }
120 | }
121 |
122 |
123 | #' Sub-fn to safely intepret grobHeight
124 | #'
125 | #' This returns the height of a grob in any real unit. If the value passed in is
126 | #' null, it returns 0. It is used in various places in `finalize_plot`.
127 | #'
128 | #' @noRd
129 | safe_grobHeight <- function(grob, unitTo = "bigpts", valueOnly = TRUE){
130 |
131 | if(is.null(grob)){
132 | if(valueOnly){
133 | return(0)
134 | } else {
135 | return(unit(0, unitTo))
136 | }
137 | }
138 |
139 | return(grid::convertHeight(grid::grobHeight(grob), unitTo, valueOnly))
140 | }
141 |
142 |
143 | #' Palette Fetcher
144 | #'
145 | #' @param which a vector of palette types to consider
146 | #' @param return Value to return. "colors", the default, returns the palette as
147 | #' a vector of colors. "type" returns the palette's type. "Exists" returns
148 | #' TRUE or FALSE based on whether the name is found in the palettes table.
149 | #'
150 | #' @describeIn viz_palette Returns details about a palette
151 | #'
152 | #' @examples
153 | #' # Identify the first two colors of the Prosperity Palette
154 | #' fetch_pal("prosperity")[1:2]
155 | #'
156 | #' # Confirm that "reds" is a sequential palette
157 | #' fetch_pal("reds", which = "sequential", return = "exists")
158 | #'
159 | #' @export
160 | fetch_pal <- function(pal,
161 | which = c("discrete", "sequential", "divergent"),
162 | return = c("colors", "type", "exists")){
163 | # basics
164 | name <- type <- NULL
165 | return <- match.arg(return)
166 | which <- match.arg(which, unique(cmapplot_globals$palettes$type), several.ok = TRUE)
167 |
168 | # filter palettes
169 | df <- dplyr::filter(
170 | cmapplot_globals$palettes,
171 | name == pal,
172 | type %in% which
173 | )
174 |
175 | # construct return
176 | if (return == "exists") {
177 | return(nrow(df) == 1)
178 | } else if (nrow(df) == 1) {
179 | return(df[[return]][[1]])
180 | } else {
181 | return(NULL)
182 | }
183 | }
184 |
185 |
186 |
187 | # ggrepel utility functions -----------------------------------------------
188 |
189 | ggname <- function(prefix, grob) {
190 | grob$name <- grobName(grob, prefix)
191 | grob
192 | }
193 |
194 | with_seed_null <- function(seed, code) {
195 | if (is.null(seed)) {
196 | code
197 | } else {
198 | withr::with_seed(seed, code)
199 | }
200 | }
201 |
202 | .pt <- 72.27 / 25.4
203 |
204 | "%||%" <- function(a, b) {
205 | if (!is.null(a)) a else b
206 | }
207 |
208 | #' Return a boolean vector of non-empty items.
209 | #'
210 | #' @param xs Vector with a mix of "expression" items, "character" items,
211 | #' and items from other classes.
212 | #' @return Boolean vector indicating which items are not empty.
213 | #' @noRd
214 | not_empty <- function(xs) {
215 | sapply(seq_along(xs), function(i) {
216 | if (is.expression(xs[i])) {
217 | return(length(nchar(xs[i])) > 0)
218 | } else {
219 | return(xs[i] != "")
220 | }
221 | })
222 | }
223 |
224 | #' Return a unit version of the argument.
225 | #'
226 | #' @param x Number or unit object.
227 | #' @return unit(x, "lines") if number or the unchanged argument if it's already
228 | #' a unit object.
229 | #' @noRd
230 | to_unit <- function(x) {
231 | # don't change arg if already unit
232 | if (is.unit(x)) {
233 | return(x)
234 | }
235 |
236 | # NA used to exclude points from repulsion calculations
237 | if (length(x) == 1 && is.na(x)) {
238 | return(NA)
239 | }
240 |
241 | unit(x, "lines")
242 | }
243 |
244 | #' Parse takes a vector of n lines and returns m expressions.
245 | #' See https://github.com/tidyverse/ggplot2/issues/2864 for discussion.
246 | #'
247 | #' parse(text = c("alpha", "", "gamma"))
248 | #' #> expression(alpha, gamma)
249 | #'
250 | #' parse_safe(text = c("alpha", "", "gamma"))
251 | #' #> expression(alpha, NA, gamma)
252 | #'
253 | #' @noRd
254 | parse_safe <- function(text) {
255 | stopifnot(is.character(text))
256 | out <- vector("expression", length(text))
257 | for (i in seq_along(text)) {
258 | expr <- parse(text = text[[i]])
259 | out[[i]] <- if (length(expr) == 0) NA else expr[[1]]
260 | }
261 | out
262 | }
263 |
264 | #' Exclude data points outside the panel ranges
265 | #' @noRd
266 | exclude_outside <- function(data, panel_scales) {
267 | if ("x.range" %in% names(panel_scales)) {
268 | xr <- panel_scales$x.range
269 | yr <- panel_scales$y.range
270 | ix <- inside(data$x, xr) & inside(data$y, yr)
271 | data <- data[ix,,drop=FALSE]
272 | } else if ("x_range" %in% names(panel_scales)) {
273 | xr <- panel_scales$x_range
274 | yr <- panel_scales$y_range
275 | ix <- inside(data$x, xr) & inside(data$y, yr)
276 | data <- data[ix,,drop=FALSE]
277 | }
278 | data
279 | }
280 |
281 | #' Exclude data points outside the panel ranges
282 | #' @noRd
283 | inside <- function(x, bounds) {
284 | is.infinite(x) | (x <= bounds[2] & x >= bounds[1])
285 | }
286 |
--------------------------------------------------------------------------------
/vignettes/plots.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Creating CMAP-themed plots"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{Creating CMAP-themed plots}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r setup, include = FALSE}
11 | knitr::opts_chunk$set(
12 | collapse = TRUE,
13 | comment = "#>",
14 | fig.width = 7,
15 | fig.asp = 400/670,
16 | fig.retina = 4,
17 | fig.align = "center",
18 | dev = "ragg_png"
19 | )
20 |
21 | library(tidyverse)
22 | library(cmapplot)
23 | unapply_cmap_default_aes() # For testing purposes
24 | ```
25 |
26 | This vignette summarizes the basic formatting that the cmapplot package can add to a `ggplot()`, including via the functions `theme_cmap()`, `geom_recessions()`, `geom_text_lastonly()`, and `apply_cmap_default_aes()`. The vignette relies on one of the sample CMAP datasets included with the package.
27 |
28 |
29 | ## The initial plot
30 |
31 | Let's start with a basic time series line graph, drawn using ggplot2's default theme (`theme_grey()`). We'll save this as `p` for later, but keep the actual data geom (in this case, `geom_line()`) separate due to how ggplot2 layers geoms.
32 |
33 | ```{r initial, message = FALSE}
34 | # load tidyverse (which includes ggplot2) and cmapplot
35 | library(tidyverse)
36 | library(cmapplot)
37 |
38 | # clean up dataset
39 | df <- transit_ridership %>%
40 | filter(system != "pace_ada") %>%
41 | mutate(system = recode_factor(system,
42 | cta_bus = "CTA bus",
43 | cta_rail = "CTA rail",
44 | metra = "Metra",
45 | pace = "Pace"
46 | ))
47 |
48 | # build plot
49 | p <- ggplot(data = df,
50 | mapping = aes(x = year, y = ridership, color = system)) +
51 | scale_y_continuous(breaks = c(0, 200, 400),
52 | limits = c(-1, 575))
53 |
54 | p + geom_line()
55 | ```
56 |
57 |
58 | ## The CMAP theme
59 |
60 | ### Basic implementation
61 |
62 | To add basic CMAP design elements to the plot, add `theme_cmap()` like you would any other ggplot2 theme.
63 |
64 | ```{r basic, message = FALSE}
65 | p + geom_line() + theme_cmap()
66 | ```
67 |
68 | ### Built-in modifiers
69 |
70 | The CMAP theme function has a variety of easy built-in modifiers. For example, by default the x- and y-axis labels are turned off, but this can be overridden. The help file `?theme_cmap` describes how to make these changes.
71 |
72 | For example, `theme_cmap()` can be used to to add a strong horizontal or vertical line (such as to delineate zero or some other threshold). Note that, on standard-resolution (non-retina) displays, `hline` and `vline` may appear as the same thickness as the plot's gridlines when viewed within R. When exported as a vector file (or raster at high enough resolution) the difference becomes apparent.
73 |
74 | When using `hline` and/or `vline`, it is important to place `theme_cmap()` *before* the primary data geom. This is because the `hline` drawn by `theme_cmap()` is a geom, and ggplot2 layers geoms in the order they are added to the plot. This ordering allows the `CTA rail` line to be drawn on top of the `hline`.
75 |
76 | ```{r mods1, message = FALSE}
77 | p + theme_cmap(ylab = "Annual Ridership (Millions)",
78 | hline = 200, # may not be immediately visible
79 | legend.max.columns = 2) +
80 | geom_line()
81 | ```
82 |
83 |
84 | `theme_cmap()` also allows users to easily add tick marks on the x- and/or the y-axes, using the argument `axisticks`. Note that here, some additional manipulation of the y-axis scale is necessary for the axis ticks to touch the lowest horizontal gridline (this is to override `ggplot2`'s default behavior, which expands the scale slightly beyond the extent of the data for aesthetic reasons).
85 | ```{r mods2, message = FALSE}
86 | p + geom_line() +
87 | scale_y_continuous(breaks = c(0, 200, 400),
88 | limits = c(-1, 575),
89 | expand = c(0, 0)) +
90 | theme_cmap(ylab = "Annual Ridership (Millions)",
91 | axisticks = "x")
92 | ```
93 |
94 | ### Overriding plotting defaults
95 |
96 | The package contains a list of default values (`cmapplot_globals$consts`) that control various plotting constants. Most of these impact the function `finalize_plot()`, but a few impact `theme_cmap()`. For a complete description of these constants, see `?cmapplot_globals`.
97 |
98 | The most important at this stage is `margin_panel_r`, which controls the distance between the right side of the plot and the right side of the plotting window. Depending on the length and location of your right-most x axis label, you may need to expand this value beyond it's default. These `consts` can be modified in the `overrides` argument:
99 |
100 | ```{r overrides, message = FALSE}
101 | p + scale_x_continuous(labels = c("1980", "1990", "2000", "2010", "2020", "A very long label")) +
102 | theme_cmap(ylab = "Annual Ridership (Millions)",
103 | hline = 200,
104 | overrides = list(margin_panel_r = 50, # the most likely override in theme_cmap()
105 | lwd_strongline = 3)) +
106 | geom_line()
107 | ```
108 |
109 | ### Further theme modifications
110 |
111 | In addition, any ggplot2 theme element can also be modified directly in `theme_cmap()` by passing valid arguments from the `ggplot2::theme()` function. In the following example, the addition of `panel.grid.major.y = element_line(color = "light gray")` modifies the default color of a horizontal grid line, changing it from black to light gray.
112 |
113 | ```{r mods3, message = FALSE}
114 | p + theme_cmap(ylab = "Annual Ridership (Millions)",
115 | panel.grid.major.y = element_line(color = "light gray")) +
116 | geom_line()
117 | ```
118 |
119 |
120 | ## Auxiliary functions
121 |
122 | The cmapplot package also includes two custom geoms that allow the user to easily add common elements used in CMAP plots that would be otherwise difficult to program.
123 |
124 | ### Include US recessions as a backdrop
125 |
126 | The function `geom_recessions()`, allows for the addition of rectangles (and text, if desired) representing US economic recessions. Similar to the `hline` example above, `geom_recessions()` should be added before the plot's primary geom (`geom_line()`) so that lines are drawn on top of recession rectangles.
127 |
128 | `ggplot()` always draws geoms *on top* of base plot elements like gridlines. The default fill and alpha values for `geom_recessions()` are the most transparent way possible to achieve CMAP palette color `#002d49` when drawn on a white background — thus impacting the color of the gridlines as little as possible.
129 |
130 | This function relies on the National Bureau of Economic Research's definitions of recessions. Details on how to update these dates, as well as how to provide your own, can be found in `geom_recessions()` and `update_recessions()`. If the most recent recession has not yet been declared over (as is the case in June 2021), the function will default to displaying this ongoing recession from its beginning through the end of the visualized data. If this is not desired (for example, if the visualization is of a projection far into the future), users can remove this ongoing recession by setting `show_ongoing = FALSE`.
131 |
132 | ```{r recessions, message = FALSE}
133 | q <- ggplot(data = df,
134 | mapping = aes(x = year, y = ridership, color = system)) +
135 | geom_recessions(ymin = 0) +
136 | geom_line() +
137 | theme_cmap(ylab = "Annual Ridership (Millions)")
138 |
139 | q
140 | ```
141 |
142 | ### Label and highlight final data point
143 |
144 | The function `geom_text_lastonly()` allows the user to label only the final point in a time series. In addition to applying the label, this function can also highlight the final point via an implicit `geom_point()`. Like `geom_text()`, the value of the label can be passed via the `mapping` argument, either in the top-line `ggplot()` or in `geom_text_lastonly()`.
145 |
146 | Due to ggplot2's underlying structure, `geom_text()` labels are clipped by the plot's default extent. Often, the right side of the plot will need to be expanded — or plot clipping turned off — for correct display of these labels. `?geom_text_lastonly` describes a number of methods to account for this.
147 |
148 | ```{r textlast, message = FALSE}
149 | q <- q + geom_text_lastonly(mapping = aes(label = round(ridership, digits = 0)),
150 | add_points = TRUE,
151 | nudge_x = 0.5) +
152 | coord_cartesian(clip = "off")
153 |
154 | q
155 | ```
156 |
157 | ### Abbreviating years in date axes
158 |
159 | By default, date axes with units in years display the full year for each axis label (e.g., 2000, 2001, 2002, 2003). In some cases, users may want to abbreviate some, but not all, of these axis labels, such as by maintaining the full year for the first label and abbreviating subsequent labels (e.g., 2000, '01, '02, '03). The function `abbr_years` enables users to do so, defaulting to abbreviating all years but the first.
160 |
161 | This function uses syntax similar to those in the `scales::label_*()` family, and can be applied to a plot via the labels parameters of the `ggplot2::scale_x_continuous` or `ggplot2::scale_x_date()` functions (or their y-axis counterparts). Users can specify which years should be abbreviated by either their value (using `full_by_year`) or their position on the axis (using `full_by_pos`). More details are available in `?abbr_years`.
162 |
163 | ```{r abbr_years, message = FALSE}
164 | p + geom_line() + theme_cmap() +
165 | scale_x_continuous(labels = abbr_years(full_by_year = c(2000)))
166 | ```
167 |
168 | ### Applying CMAP default aesthetics
169 |
170 | Every ggplot2 "geom" has default aesthetics that cannot be modified by a ggplot2 theme (and therefore, cannot be modified by `theme_cmap()`). Notice, for example, that the text drawn in the plot via `geom_text_lastonly()` and `geom_recessions()` still appears in Arial (R's default font), although the legend and axis fonts appear in Whitney. This is automatically corrected in `finalize_plot()`. However, if you'd like to see these impacts at this stage, you can override ggplot2's default aesthetics for line and text geoms with CMAP defaults via `apply_cmap_default_aes()`.
171 |
172 | ```{r aes}
173 | apply_cmap_default_aes()
174 |
175 | q
176 | ```
177 |
178 | It is important to note that this change is "sticky" for the duration of the session, but you can reverse the change with `unapply_cmap_default_aes()`. This function will revert to whatever the default aesthetics were before cmapplot was loaded.
179 |
180 |
181 | ## Debug mode
182 |
183 | In addition, `theme_cmap()` provides a debug mode in which it draws outlines around the rectangular elements in the plot. This can help the user understand what is being drawn and identify additional modifications that they might want to make via `overrides` or `ggplot2::theme()` arguments:
184 |
185 | ```{r debug, message = FALSE}
186 | ggplot(data = df,
187 | mapping = aes(x = year, y = ridership, color = system)) +
188 | geom_recessions(ymin = 0) +
189 | geom_line() +
190 | theme_cmap(ylab = "Annual Ridership (Millions)",
191 | debug = TRUE)
192 | ```
193 |
--------------------------------------------------------------------------------
/vignettes/finalize.Rmd:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Finalizing and exporting CMAP-themed plots"
3 | output: rmarkdown::html_vignette
4 | vignette: >
5 | %\VignetteIndexEntry{Finalizing and exporting CMAP-themed plots}
6 | %\VignetteEngine{knitr::rmarkdown}
7 | %\VignetteEncoding{UTF-8}
8 | ---
9 |
10 | ```{r setup, include = FALSE}
11 | knitr::opts_chunk$set(
12 | collapse = TRUE,
13 | comment = "#>",
14 | fig.width = 670/72,
15 | fig.asp = 400/670,
16 | fig.retina = 4,
17 | fig.align = "center",
18 | out.width = "100%",
19 | dev = "ragg_png"
20 | )
21 |
22 | library(tidyverse)
23 | library(cmapplot)
24 |
25 | # clean up dataset
26 | df <- transit_ridership %>%
27 | filter(system != "pace_ada") %>%
28 | mutate(system = recode_factor(system,
29 | cta_bus = "CTA bus",
30 | cta_rail = "CTA rail",
31 | metra = "Metra",
32 | pace = "Pace"
33 | ))
34 |
35 | # build plot
36 | p <- ggplot(data = df,
37 | mapping = aes(x = year, y = ridership, color = system)) +
38 | geom_recessions(ymin = 0) +
39 | geom_line() +
40 | geom_text_lastonly(
41 | mapping = aes(label = round(ridership, digits = 0)),
42 | add_points = TRUE,
43 | nudge_x = 0.5) +
44 | coord_cartesian(clip = "off") +
45 | theme_cmap()
46 | ```
47 |
48 | `finalize_plot()` will place a ggplot into a frame defined by CMAP design standards. It will align your title and caption to the left, add a horizontal line on top, and make other adjustments. It can show you the final plot and/or export it as a raster or vector file. This function will not apply CMAP design standards to the plot itself; use `theme_cmap()` for that.
49 |
50 | In this vignette we will use the final version of the line chart developed in `vignette("plots")` to describe standard use of the `finalize_plot()` function. That plot is referenced in the following examples as `p`. The function has numerous additional customization options built in, accepting 16 (or more) arguments. Refer to the object documentation, `?finalize_plot`, for detailed information on all arguments.
51 |
52 |
53 | ## Basic implementation
54 |
55 | ### Finalizing a plot
56 |
57 | After creating a plot and applying `theme_cmap()`, use `finalize_plot()` to complete the implementation of CMAP design standards. You will probably want to set at least the `title` and `caption`, although the function will extract them from the ggplot if they were specified.
58 |
59 | As you are preparing the plot, you will likely want to view it within R. Do this by leaving leaving the default `mode = "plot"` to send the finished plot to the "Plots" tab within RStudio. The plot will show up "actual size" (depending on your screen's resolution) surrounded by a gray canvas. If you want to view the plot in a separate window, you can select the "Zoom" button at the top left of the plot. This may be especially useful for large plots that cannot easily be displayed within RStudio's default plotting window.
60 |
61 | ```{r finalize1, fig.width=11, out.width="100%"}
62 | finalize_plot(plot = p,
63 | title = "Annual unlinked passenger trips (in millions)",
64 | caption = "Source: Chicago Metropolitan Agency for Planning
65 | analysis of Regional Transportation Authority data")
66 | ```
67 |
68 | ### Exporting a plot
69 |
70 | Once you are happy with your plot, export it using `finalize_plot()` with one or more of the write modes `c("svg", "ps", "pdf", "png", "tiff", "jpeg")` as well as the filename argument. If Communications staff will be modifying your graphic, they will require one of the vector formats (preferably PDF). While many raster formats are available, PNG is *strongly* recommended over the others for the best balance of filesize and visual fidelity.
71 |
72 | You may specify multiple modes simultaneously using the form `mode = c("png", "pdf", "plot")`. That would export the plot as both a PDF and PNG, as well as display it in the plotting window of your R console.
73 |
74 | Some additional notes:
75 |
76 | - If the full file path is not specified, the file will be exported to your current working directory (check with `getwd()`, change with `setwd(dir)`).
77 |
78 | - If a file with the name specified already exists in the specified directory, it will not be overwritten unless the user sets `overwrite = TRUE`.
79 |
80 | - When naming your exports, you may but do not need to include the extension (e.g., `filename = "my_chart"`). The function will automatically add the appropriate extension to each of your exported files (e.g., `"my_chart.pdf"`, `"my_chart.png"`). Leaving off the extension is recommended if you're specifying multiple export modes in the same call.
81 |
82 |
83 | ```{r finalize2-forshow, eval=FALSE, echo=TRUE}
84 | # Finalize and export plot to PNG and PDF
85 | finalize_plot(plot = p,
86 | title = "Annual unlinked passenger trips (in millions)",
87 | caption = "Source: Chicago Metropolitan Agency for Planning
88 | analysis of Regional Transportation Authority data",
89 | mode = c("png", "pdf"),
90 | filename = "finalized_plot")
91 | ```
92 |
93 |
94 | ```{r finalize2, eval=TRUE, echo=FALSE, message=FALSE}
95 | finalize_plot(plot = p,
96 | title = "Annual unlinked passenger trips (in millions)",
97 | caption = "Source: Chicago Metropolitan Agency for Planning
98 | analysis of Regional Transportation Authority data")
99 | ```
100 |
101 |
102 | ## Basic customization
103 |
104 | While `finalize_plot()` can be run successfully with very few arguments, the function allows many further customizations, a number of which are described here.
105 |
106 | ### Top-level position adjustments
107 |
108 | In addition to setting the plot's `height` and `width`, `finalize_plot()` has a number of top-level arguments that impact the final layout. For example, you can change the width of the sidebar, alter caption alignment, or change the graphic's background color. Changing the background color can be helpful if you know that the graphic will eventually be placed on an inked page.
109 |
110 | ```{r finalize3, message=FALSE}
111 | # A modified finalized plot
112 | finalize_plot(plot = p,
113 | title = "Annual unlinked passenger trips (in millions)",
114 | caption = "Source: Chicago Metropolitan Agency for Planning
115 | analysis of Regional Transportation Authority data",
116 | sidebar_width = 1.8,
117 | caption_align = 1,
118 | fill_bg = "cornsilk")
119 | ```
120 |
121 | ### Finalizing a plot with no sidebar
122 |
123 | One special case of a top-level position adjustment is removing the sidebar altogether by setting `sidebar_width = 0`. This is generally preferred when creating graphics to embed in a Word/PDF report (as opposed to a web page or presentation slide). Titles and captions, if specified, are moved to above and below the plot element, respectively. Note that this has an impact on what margins are drawn where. See the section [Many, many margins] for more on this.
124 |
125 | ```{r finalize4, message=FALSE}
126 | # A finalized line graph, with no sidebar
127 | finalize_plot(plot = p,
128 | title = "Annual unlinked passenger trips (in millions)",
129 | caption = "Source: Chicago Metropolitan Agency for Planning
130 | analysis of Regional Transportation Authority data",
131 | sidebar_width = 0)
132 | ```
133 |
134 | ### Title and caption formatting
135 |
136 | The title and caption blocks take HTML formatting tags, which you can use to manually set line breaks and apply other font formatting.
137 |
138 | ```{r finalize5, message=FALSE}
139 | # A finalized line graph, with text tweaks
140 | finalize_plot(plot = p,
141 | title = "Annual unlinked passenger trips
(in millions)",
142 | caption = 'Source: Chicago
143 | Metropolitan Agency for Planning analysis of
144 | RTA1 data.
145 |
146 | 1 Regional Transportation Authority')
147 | ```
148 |
149 | ## Advanced customization
150 |
151 | ### Using debug mode to fine-tune your plot
152 |
153 | `finalize_plot()` has a built-in visual debugging tool that helps the user identify the positions of various elements of the finished graphic and how they relate to one another. Setting `debug = TRUE` will draw outlines around every rectangular "grob" in the graphic:
154 |
155 | ```{r finalize6, message=FALSE}
156 | # A debugged finalized plot
157 | finalize_plot(plot = p,
158 | title = "Annual unlinked passenger trips (in millions)",
159 | caption = "Source: Chicago Metropolitan Agency for Planning
160 | analysis of Regional Transportation Authority data",
161 | debug = TRUE)
162 | ```
163 |
164 | ### Overriding plotting constants
165 |
166 | Default values in `finalize_plot()` attempt to reflect CMAP design standards using constants. The list of preset values can be accessed by calling `get_cmapplot_globals()`, while individual presets can be accessed using `get_cmapplot_global()`. Users can manually adjust these constants by passing a named list to the `overrides` argument. For example, the chart below uses `overrides` to modify the margin below the title (`margin_title_b`), the margin to the left of the sidebar (`margin_sidebar_l`), and the margin above the legend (`margin_legend_t`).
167 |
168 | The [Many, many margins] section of this article describes most of these `consts` visually. To learn more about all possible overrides, see `?set_cmapplot_global`.
169 |
170 | ```{r finalize7, message=FALSE}
171 | # A finalized plot with some formatting overrides
172 | finalize_plot(plot = p,
173 | title = "Annual unlinked passenger trips (in millions)",
174 | caption = "Source: Chicago Metropolitan Agency for Planning
175 | analysis of Regional Transportation Authority data",
176 | debug = TRUE,
177 | overrides = list(margin_title_b = 30,
178 | margin_sidebar_l = 10,
179 | margin_legend_t = 15))
180 | ```
181 |
182 | ### Unshifting the legend
183 |
184 | By default, `finalize_plot()` will attempt to extract legend from the ggplot and draw it separately. This allows for justifying the legend to the left edge of the plotting area (`ggplot2` only allows the legend to left-justify to the y axis). If this attempted shift is unwanted or results in an error, the legend alignment of the original plot can be kept by setting `legend_shift = FALSE`. Note that in this situation, the debug boxes indicate that `finalize_plot()` has not separated the legend from the plot.
185 |
186 | ```{r finalize8, message=FALSE}
187 | # A finalized plot with an un-modified legend
188 | finalize_plot(plot = p,
189 | title = "Annual unlinked passenger trips (in millions)",
190 | caption = "Source: Chicago Metropolitan Agency for Planning
191 | analysis of Regional Transportation Authority data",
192 | debug = TRUE,
193 | legend_shift = FALSE)
194 | ```
195 |
196 | ### Many, many margins
197 |
198 | There is a fairly long list of possible margins that can be customized using the `overrides` argument of `finalize_plot()`. You can read more about the available options for customization in `?set_cmapplot_global`.
199 |
200 | Here, the margins are visualized as they impact a finalized plot that has a sidebar:
201 |
202 |
203 |
204 | Here, the same margins are visualized as they impact a finalized plot with no sidebar:
205 |
206 |
207 |
--------------------------------------------------------------------------------