| Title: | Executive-Grade Themes and Helpers for 'ggplot2' |
|---|---|
| Description: | An opinionated 'ggplot2' extension for executive-grade consulting output, built to make slides and reports look polished without per-project tweaking. Ships a set of archetype themes that match common consulting deliverables (situation assessment, roadmap, benchmark, deep dive) and pairs them with coordinated color palettes and scale helpers. Locale-aware label functions format numbers, currency, and dates for Brazilian Portuguese and English audiences. A data-aware polish layer inspects the plot and applies sensible finishing touches, so charts stay readable and consistent across an entire engagement. |
| Authors: | Vinicius Oike [aut, cre, cph] |
| Maintainer: | Vinicius Oike <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.1 |
| Built: | 2026-10-05 07:22:35 UTC |
| Source: | https://github.com/viniciusoike/ggconsulting |
Monthly observations of five headline Brazilian macro series from
2012-03 through 2024-12. Wide format: one row per month, one column
per indicator. Snapshot frozen at 2024-12-31. Suitable for
theme_editorial() demos and ct_locale("pt-BR") formatting.
br_macrobr_macro
A data frame with 154 rows and 6 columns:
First day of the month (Date).
Selic accumulated in the month, annualized using base 252, % a.a. (numeric).
IPCA accumulated over the trailing 12 months, % (numeric).
IBC-Br activity index, seasonally adjusted, 2002=100 (numeric).
USD/BRL exchange rate (sale), BRL per USD, end-of-month (numeric).
PNADC unemployment rate, % (numeric).
All source series are monthly. The usd_brl series is the BCB sale
rate at the end of the period; dates are normalized to the first day of
each month in this snapshot.
Banco Central do Brasil, Sistema Gerenciador de Séries Temporais
(SGS), series 4189, 13522, 24364, 3696, and 24369. Series 24369 is
PNADC data from IBGE redistributed through SGS. Fetched via the rbcb
package. The snapshot ends on 2024-12-31; values are rounded and
transformed in this repository, and this is not an official current BCB
or IBGE release. See data-raw/br_macro.R and
https://www3.bcb.gov.br/sgspub/.
head(br_macro)head(br_macro)
Simulated quarterly revenue, COGS, EBITDA, and headcount for five
business units of a mid-cap Brazilian conglomerate, spanning 16
quarters (2021-Q1 through 2024-Q4). Suitable for demos of
theme_strategy(), stacked-bar ct_finish() value labels, and
fmt_brl(). All monetary values are in millions of Brazilian Real
(R$ MM).
bu_quarterlybu_quarterly
A data frame with 80 rows and 6 columns:
First day of the calendar quarter (Date).
Factor with 5 levels: Industrial, Consumer, Health, Logistics, Digital.
Net revenue, R$ MM (numeric).
Cost of goods sold, R$ MM (numeric).
EBITDA, R$ MM (numeric); can be negative.
Period-end full-time-equivalent employees (integer).
Synthetic data generated by the ggconsulting authors. It does not
describe a real company, financial result, or employee population. See
data-raw/bu_quarterly.R.
head(bu_quarterly)head(bu_quarterly)
Simulated quarterly Net Promoter Score for three client segments
(Enterprise, Mid-Market, SMB) across 12 quarters (2022-Q1 through
2024-Q4). Suitable for line-chart demos with last-point labels and
fmt_delta() / fmt_pct().
client_npsclient_nps
A data frame with 36 rows and 4 columns:
First day of the calendar quarter (Date).
Factor with 3 levels: Enterprise, Mid-Market, SMB.
Net Promoter Score, integer in [-100, 100].
Number of survey responses in the period (integer).
Synthetic data generated by the ggconsulting authors. It does not
describe real clients, survey respondents, or survey results. See
data-raw/client_nps.R.
head(client_nps)head(client_nps)
ct_set_defaults() overrides ggplot2 aesthetic defaults via
ggplot2::update_geom_defaults(). v0.1 sets a single override:
geom_point size = 2.5. ct_unset_defaults() restores whatever
values were active the first time ct_set_defaults() ran — not
ggplot2's untouched baseline.
Originals are captured once into a package-private environment, so
repeated ct_set_defaults() calls are idempotent. Column width and
linewidth are handled elsewhere — see ct_col() / ct_line() for
explicit formal overrides, or apply ct_theme() / theme_strategy()
for linewidth via from_theme().
ct_set_defaults() ct_unset_defaults()ct_set_defaults() ct_unset_defaults()
Both functions return invisible(NULL).
ct_set_defaults() ct_unset_defaults()ct_set_defaults() ct_unset_defaults()
Companion to ct_theme() that runs after the geom layer is built,
so it can inspect the data + active geom to inject value labels,
sorting, highlighting, end labels, and scale expansion. Compose with
+, after the geoms.
ct_finish( values = FALSE, sort = NULL, label_fmt = NULL, highlight = NULL, end_labels = FALSE, end_points = FALSE, axis_y = NULL, mirror_y = FALSE, expand = "auto", muted_color = "#A8A4A0" )ct_finish( values = FALSE, sort = NULL, label_fmt = NULL, highlight = NULL, end_labels = FALSE, end_points = FALSE, axis_y = NULL, mirror_y = FALSE, expand = "auto", muted_color = "#A8A4A0" )
values |
|
sort |
One of |
label_fmt |
Either a formatter function (anything that maps a
numeric vector to a character vector), or one of the shortcut names
|
highlight |
Value(s) of the x aesthetic to emphasise. Matching
bars use the active palette's main colour; non-matching bars use
|
end_labels |
For line plots: |
end_points |
For line plots: when |
axis_y |
Moves the y axis. |
mirror_y |
When |
expand |
|
muted_color |
Fill / colour used for non-highlighted categories. |
A ct_finish object, added to a plot via +. The
ggplot_add() method composes the requested layers and scales.
library(ggplot2) d <- data.frame(g = LETTERS[1:5], v = c(3, 8, 5, 12, 7)) p <- ggplot(d, aes(g, v)) + geom_col() + ct_finish(values = TRUE, sort = "desc", label_fmt = "brl", highlight = "D") + theme_strategy()library(ggplot2) d <- data.frame(g = LETTERS[1:5], v = c(3, 8, 5, 12, 7)) p <- ggplot(d, aes(g, v)) + geom_col() + ct_finish(values = TRUE, sort = "desc", label_fmt = "brl", highlight = "D") + theme_strategy()
Factory functions: each returns a function compatible with
scales::label_* (callable on a numeric vector). Marks (thousands,
decimals) and currency symbols come from the active ggconsulting
locale, set via ct_locale().
fmt_number() — plain numbers with locale separators.
fmt_brl() — Brazilian Real. Always renders as R$ regardless of
active locale; the locale argument lets you override marks.
fmt_currency() — uses the active locale's currency symbol.
fmt_pct() — percentages. By default interprets input as a
fraction (0.5 → "50%"); pass scale = 1 when the input is
already in percent units (50 → "50%").
fmt_delta() — percentage-point-style signed deltas
(+1,2pp / -0,3pp / 0,0pp).
fmt_month() — Date / POSIXct → localised month string.
Negatives default to a minus prefix; currency helpers also support
style = "accounting", which wraps negatives in parentheses. Currency
rendering uses a non-breaking space (U+00A0) between symbol and
number so the pair never wraps across lines.
fmt_number(decimals = 0, locale = NULL) fmt_brl(decimals = 2, style = c("minus", "accounting"), locale = NULL) fmt_currency(decimals = 2, style = c("minus", "accounting"), locale = NULL) fmt_pct(decimals = 1, scale = 100, locale = NULL, accuracy = NULL) fmt_delta(decimals = 1, suffix = "pp", locale = NULL) fmt_month(format = c("abbr", "full"), locale = NULL)fmt_number(decimals = 0, locale = NULL) fmt_brl(decimals = 2, style = c("minus", "accounting"), locale = NULL) fmt_currency(decimals = 2, style = c("minus", "accounting"), locale = NULL) fmt_pct(decimals = 1, scale = 100, locale = NULL, accuracy = NULL) fmt_delta(decimals = 1, suffix = "pp", locale = NULL) fmt_month(format = c("abbr", "full"), locale = NULL)
decimals |
Number of decimal places. |
locale |
Optional locale name. Defaults to the active locale. |
style |
|
scale |
Multiplier applied to the input before rendering, for
|
accuracy |
Optional explicit accuracy passed to
|
suffix |
Suffix for |
format |
|
A formatter function: function(x) character.
fmt_number(decimals = 1)(1234.5) fmt_brl()(c(1000, -500)) fmt_pct(decimals = 0)(0.5) fmt_pct(decimals = 1, scale = 1)(50) fmt_delta()(c(1.2, -0.3, 0)) fmt_month()(as.Date("2026-08-15"))fmt_number(decimals = 1)(1234.5) fmt_brl()(c(1000, -500)) fmt_pct(decimals = 0)(0.5) fmt_pct(decimals = 1, scale = 1)(50) fmt_delta()(c(1.2, -0.3, 0)) fmt_month()(as.Date("2026-08-15"))
Three-line pass-throughs that ship consulting-grade defaults for
ggplot2::geom_col() width, ggplot2::geom_line() linewidth, and
ggplot2::geom_point() size. Use them when you want the defaults
baked into the call site; plain geom_line() will also pick up
linewidth from ct_theme() / theme_strategy() via from_theme(),
and geom_point() size is autoloaded by ct_set_defaults().
ct_col(..., width = 0.8) ct_line(..., linewidth = 0.7) ct_point(..., size = 2.5)ct_col(..., width = 0.8) ct_line(..., linewidth = 0.7) ct_point(..., size = 2.5)
... |
Forwarded to the underlying ggplot2 constructor. |
width |
Column width. Defaults to 0.8 (vs ggplot2's 0.9). |
linewidth |
Line width. Defaults to 0.7 (vs ggplot2's 0.5). |
size |
Point size. Defaults to 2.5 (vs ggplot2's 1.5). |
A ggplot2 ggplot2::layer() object.
ct_col()'s default width = 0.8 is in x-axis units. On a Date
x-axis that is 0.8 days, which renders bars as slivers when the
data is spaced quarterly or monthly. For bar charts, convert the
x variable to either an ordered factor (e.g. "21Q1", "21Q2", ...)
or a numeric index before plotting; line charts on Date are fine.
library(ggplot2) d <- data.frame(g = c("A", "B", "C"), v = c(3, 5, 2)) p_col <- ggplot(d, aes(g, v)) + ct_col() p_line <- ggplot(economics, aes(date, unemploy)) + ct_line() p_point <- ggplot(mtcars, aes(wt, mpg)) + ct_point()library(ggplot2) d <- data.frame(g = c("A", "B", "C"), v = c(3, 5, 2)) p_col <- ggplot(d, aes(g, v)) + ct_col() p_line <- ggplot(economics, aes(date, unemploy)) + ct_line() p_point <- ggplot(mtcars, aes(wt, mpg)) + ct_point()
Stores the choice in options(ggconsulting.locale = ...). The active
locale is read by the formatter helpers (fmt_number(),
fmt_currency(), fmt_month(), etc.) when their locale argument
is NULL. Defaults to "pt-BR"; "en-US" is always available.
ct_locale(locale = c("pt-BR", "en-US"))ct_locale(locale = c("pt-BR", "en-US"))
locale |
One of |
Does not touch Sys.setlocale() — that's OS-dependent and breaks
on Windows CI. ggconsulting ships its own month tables and formatting
marks instead.
The previous locale, invisibly. Use it to round-trip:
old <- ct_locale("en-US"); ...; ct_locale(old).
old <- ct_locale("en-US") ct_locale(old)old <- ct_locale("en-US") ct_locale(old)
Returns the hex colour vector for a named palette, optionally subsetting
or interpolating to n colours. Called with no arguments, returns the
names of all available palettes.
ct_palette(palette = NULL, n = NULL, reverse = FALSE)ct_palette(palette = NULL, n = NULL, reverse = FALSE)
palette |
Palette name (e.g. |
n |
Number of colours to return. When |
reverse |
Reverse palette order before subsetting. Defaults to
|
A character vector of hex colours, or (when palette is NULL)
a character vector of palette names.
# List available palettes ct_palette() # Full palette ct_palette("strategy_navy") # First 3 colours ct_palette("strategy_navy", n = 3) # Interpolate to 9 colours ct_palette("strategy_navy", n = 9)# List available palettes ct_palette() # Full palette ct_palette("strategy_navy") # First 3 colours ct_palette("strategy_navy", n = 3) # Interpolate to 9 colours ct_palette("strategy_navy", n = 9)
Returns a ggplot showing palettes as colour tiles with the hex value
overlaid in monospace. With palette = NULL, every palette shipped
in .ct_palettes is shown faceted.
ct_palette_show(palette = NULL)ct_palette_show(palette = NULL)
palette |
Palette name (e.g. |
A ggplot object.
p_all <- ct_palette_show() p_one <- ct_palette_show("strategy_emerald") p_vec <- ct_palette_show(c("#0F4D38", "#177B57", "#3DA876"))p_all <- ct_palette_show() p_one <- ct_palette_show("strategy_emerald") p_vec <- ct_palette_show(c("#0F4D38", "#177B57", "#3DA876"))
Discrete and continuous scales backed by ggconsulting palettes. Discrete
variants interpolate (with a warning) when the data has more levels than
the palette can hold. Continuous variants gradient across all palette
colours via ggplot2::scale_color_gradientn() /
ggplot2::scale_fill_gradientn().
British spellings (scale_colour_ct(), scale_colour_ct_c()) are
provided as aliases.
scale_color_ct(palette = "strategy_navy", reverse = FALSE, ...) scale_colour_ct(palette = "strategy_navy", reverse = FALSE, ...) scale_fill_ct(palette = "strategy_navy", reverse = FALSE, ...) scale_color_ct_c(palette = "strategy_navy", direction = 1, ...) scale_colour_ct_c(palette = "strategy_navy", direction = 1, ...) scale_fill_ct_c(palette = "strategy_navy", direction = 1, ...)scale_color_ct(palette = "strategy_navy", reverse = FALSE, ...) scale_colour_ct(palette = "strategy_navy", reverse = FALSE, ...) scale_fill_ct(palette = "strategy_navy", reverse = FALSE, ...) scale_color_ct_c(palette = "strategy_navy", direction = 1, ...) scale_colour_ct_c(palette = "strategy_navy", direction = 1, ...) scale_fill_ct_c(palette = "strategy_navy", direction = 1, ...)
palette |
Palette name (e.g. |
reverse |
Reverse palette order before mapping. Defaults to |
... |
Forwarded to the underlying ggplot2 scale constructor. |
direction |
|
A ggplot2 scale.
library(ggplot2) p_d <- ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point() + scale_color_ct("strategy_azure") p_c <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + geom_raster() + scale_fill_ct_c("strategy_emerald")library(ggplot2) p_d <- ggplot(mtcars, aes(wt, mpg, colour = factor(cyl))) + geom_point() + scale_color_ct("strategy_azure") p_c <- ggplot(faithfuld, aes(waiting, eruptions, fill = density)) + geom_raster() + scale_fill_ct_c("strategy_emerald")
Flexible builder behind the archetype presets (theme_strategy() and
friends). Composes ggplot2::theme_minimal() with executive-output
overrides via theme_sub_*() helpers, sets the theme geom element
so from_theme()-aware layers (e.g. ggplot2::geom_line()) inherit
the resolved linewidth and main colour, and applies the resolved
font with a fallback chain.
ct_theme( palette = "strategy_navy", font = "Inter", font_fallback = c("Helvetica Neue", "Arial", "sans"), density = c("normal", "tight", "loose"), context = c("presentation", "report", "screen"), base_size = NULL, main_color = NULL, paper = NULL )ct_theme( palette = "strategy_navy", font = "Inter", font_fallback = c("Helvetica Neue", "Arial", "sans"), density = c("normal", "tight", "loose"), context = c("presentation", "report", "screen"), base_size = NULL, main_color = NULL, paper = NULL )
palette |
Palette name (e.g. |
font |
Preferred font family. |
font_fallback |
Character vector of fallback families to try if
|
density |
One of |
context |
One of |
base_size |
Base font size. If |
main_color |
Routed into the theme |
paper |
Figure ground colour. |
A ggplot2::theme() object.
library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + ct_theme()library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + ct_theme()
Eight-row ordered breakdown decomposing the year-over-year EBITDA change for the fictional conglomerate behind bu_quarterly into volume, price, cost, mix, FX, and one-off effects. The first and last rows are absolute levels; the six intermediate rows are signed deltas that reconcile the endpoints. Designed for waterfall charts.
ebitda_bridgeebitda_bridge
A data frame with 8 rows and 3 columns:
Ordered factor naming the bridge step.
R$ MM (numeric). Absolute level for endpoint rows; signed delta for intermediate rows.
Factor with 3 levels: "total" for endpoint rows,
"increase" or "decrease" for deltas.
Synthetic data generated by the ggconsulting authors. It does not
describe a real company or financial result. See
data-raw/ebitda_bridge.R.
ebitda_bridgeebitda_bridge
Used to gate font-dependent code paths and tests, and by ct_theme()
to walk its font_fallback chain.
has_font(name)has_font(name)
name |
Font family name, as it appears in the |
Checks both font tables systemfonts maintains: families installed on
the operating system (systemfonts::system_fonts()) and families
registered for the current session with
systemfonts::register_font() (systemfonts::registry_fonts()).
Registered fonts do not appear in the system table, so checking only
that one would silently reject a corporate font a user had registered
from a file rather than installed.
TRUE if name matches an available family, FALSE
otherwise. Vectorised over name.
has_font("Arial") # Registered fonts count as available, so a client brand font you # register from a file can be used by name: ## Not run: systemfonts::register_font("ClientSans", plain = "~/fonts/ClientSans.ttf") has_font("ClientSans") ct_theme(font = "ClientSans") ## End(Not run)has_font("Arial") # Registered fonts count as available, so a client brand font you # register from a file can be used by name: ## Not run: systemfonts::register_font("ClientSans", plain = "~/fonts/ClientSans.ttf") has_font("ClientSans") ct_theme(font = "ClientSans") ## End(Not run)
Monthly closing values and total monthly return for the Ibovespa
(IBOV) and six B3 sector indices, covering 2020-01 through 2024-12.
Snapshot frozen at 2024-12-31. Long format: one row per
(sector_index, month). Suitable for theme_finance() demos
and small-multiples.
ibov_sectorsibov_sectors
A data frame with ~420 rows and 4 columns:
First day of the month (Date).
Factor with 7 levels: IBOV, IFNC, INDX, IMAT, IEEX, ICON, IMOB.
End-of-month index level (numeric).
Monthly arithmetic return, fraction (numeric);
NA for the first month of each series.
B3 S.A. – Brasil, Bolsa, Balcão, historical index series for the
Ibovespa and B3 sector indices, fetched via the rb3 package. The
snapshot ends on 2024-12-31; close and return_m are transformed or
derived in this repository. B3 does not endorse this package. See
data-raw/ibov_sectors.R and
https://www.b3.com.br/pt_br/market-data-e-indices/indices/indices-de-segmentos-e-setoriais/.
head(ibov_sectors)head(ibov_sectors)
Downloads and installs the font families used by the three archetype
themes (theme_strategy(), theme_finance(), theme_editorial()).
All fonts are OFL or Apache-2.0 licensed.
install_consulting_fonts(fonts = NULL, dest = NULL, quiet = FALSE)install_consulting_fonts(fonts = NULL, dest = NULL, quiet = FALSE)
fonts |
Character vector of family names to install, or |
dest |
Destination directory. |
quiet |
Suppress informational messages. Errors are always
emitted. Defaults to |
Variable-weight families (Inter, Source Sans 3, Source Serif 4,
IBM Plex Sans) are downloaded as variable .ttf files containing all
weights (Light through Bold and beyond). Lato is downloaded as four
static .ttf files (Regular, Bold, Italic, Light).
Invisibly, a character vector of installed file paths.
Installing to the default destination writes font files into your home
directory and downloads roughly 9 MB from the network. Because that is
outside the R session, this function never does it silently: in an
interactive session it asks for confirmation first, and in a
non-interactive one it aborts. To install unattended, either pass an
explicit dest or set options(ggconsulting.font_consent = TRUE).
No confirmation is asked when dest is supplied, since the caller has
then named the directory themselves.
## Not run: install_consulting_fonts() install_consulting_fonts("Inter") # Unattended, into a directory you choose: install_consulting_fonts("Inter", dest = tempdir()) ## End(Not run)## Not run: install_consulting_fonts() install_consulting_fonts("Inter") # Unattended, into a directory you choose: install_consulting_fonts("Inter", dest = tempdir()) ## End(Not run)
Preset path through ct_theme() tuned for analyst notes and market
commentary: serif typography ("Source Serif 4" with a Georgia /
Times / serif fallback chain), a slightly larger title with tighter
leading, and italic subtitles for typographic personality.
theme_editorial(main_color = NULL, ...)theme_editorial(main_color = NULL, ...)
main_color |
Routed into the theme |
... |
Forwarded to |
A ggplot2::theme() object.
library(ggplot2) p <- ggplot(economics, aes(date, unemploy)) + geom_line() + theme_editorial()library(ggplot2) p <- ggplot(economics, aes(date, unemploy)) + geom_line() + theme_editorial()
Preset path through ct_theme() tuned for finance reports and pitch
books: humanist sans typography ("Source Sans 3" with an Inter /
Helvetica Neue / Arial fallback chain), no gridlines, y-axis ticks to
read levels against, and denser defaults (density = "tight",
context = "report") so plots read closer to a printed page than a
slide.
theme_finance(main_color = NULL, density = "tight", context = "report", ...)theme_finance(main_color = NULL, density = "tight", context = "report", ...)
main_color |
Routed into the theme |
density |
Passed to |
context |
Passed to |
... |
Forwarded to |
Sans rather than serif follows the institutional chart packs the
archetype is drawn from, which set their exhibits in a humanist sans
and reserve serif for body text. Pair the bare axis with
ct_finish(mirror_y = TRUE) to repeat the ticks on the right edge,
which is how those references let the eye track a level across a wide
panel without gridlines.
A ggplot2::theme() object.
library(ggplot2) p <- ggplot(economics, aes(date, unemploy)) + geom_line() + theme_finance()library(ggplot2) p <- ggplot(economics, aes(date, unemploy)) + geom_line() + theme_finance()
Preset path through ct_theme() tuned for a minimal,
generous-whitespace, navy-default look inspired by top-tier global
strategy consultancies.
theme_strategy(main_color = NULL, ...)theme_strategy(main_color = NULL, ...)
main_color |
Routed into the theme |
... |
Forwarded to |
A ggplot2::theme() object.
library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_strategy()library(ggplot2) p <- ggplot(mtcars, aes(wt, mpg)) + geom_point() + theme_strategy()