R defaults
_defaults.R
library(ggplot2)
library(ggdark)
library(showtext)
library(colorspace)
library(ggthemes)
library(gt)
library(rlang)
# get plot fonts
font_add_google(name = "Public Sans", family = "Public Sans")
showtext_auto()
# Set global variable for setting fonts
# that aren't set by theme(text=...)
<- "Public Sans"
PLOT_FONT
# from the theme _variables.scss
<- "#222222"
body_bg <- darken("#375a7f", 0.50)
plot_bg <- lighten(
major
plot_bg,amount = 0.25
)<- lighten(
minor
plot_bg,amount = 0.125
)<- lighten(plot_bg, 0.5)
strip_bg
<- "#EE6677"
ptol_red <- "#4477AA"
ptol_blue
theme_set(theme_minimal(base_size = 16) +
theme(text = element_text(family = "Public Sans"),
plot.background = element_rect(fill = "white", colour = NA),
panel.background = element_rect(fill = "white", colour = NA),
panel.grid = element_blank(),
legend.key = element_blank(),
#strip.background = element_rect(fill = strip_bg),
#strip.text = element_text(color = "white"),
axis.ticks = element_blank(),
axis.line = element_line(color = "grey60", linewidth = 0.2),
legend.background = element_blank()))
<- function(){
theme_dark theme(
#panel.border = element_blank(),
text = element_text(family = "Public Sans", colour = "white"),
axis.text = element_text(colour = "white"),
rect = element_rect(colour = "#222", fill = "#222"),
plot.background = element_rect(fill = "#222", colour = NA),
panel.background = element_rect(fill = "#424952"),
strip.background = element_rect(fill="#3d3d3d"),
strip.text = element_text(color = "white")
)
}
<- function(plot){
dark_render ::invert_geom_defaults()
ggdark::try_fetch(
rlangprint(plot),
error = function(cnd){
::invert_geom_defaults()
ggdarkabort("Failed.", parent = cnd)
}
)::invert_geom_defaults()
ggdark
}
<- function(){
theme_no_y theme(
axis.text.y = element_blank(),
axis.title.y = element_blank(),
panel.grid.major.y = element_blank()
)
}
<- function(){
theme_no_x theme(
axis.text.x = element_blank(),
axis.title.x = element_blank(),
panel.grid.major.x = element_blank()
)
}
= function(out.width, out.width.default = 0.7, fig.width.default = 6) {
out2fig * out.width / out.width.default
fig.width.default
}
options(
ggplot2.discrete.colour = lapply(1:12, ggthemes::ptol_pal()),
ggplot2.discrete.fill = lapply(1:12, ggthemes::ptol_pal()),
ggplot2.ordinal.colour = \(...) scale_color_viridis_d(option = "G", direction = -1, ...),
ggplot2.ordinal.fill = \(...) scale_fill_viridis_d(option = "G", direction = -1, ...),
ggplot2.continuous.colour = \(...) scico::scale_color_scico(palette = "batlow", ...),
ggplot2.continuous.fill = \(...) scico::scale_fill_scico(palette = "batlow", ...)
)
# set a crop: true hook
::knit_hooks$set(crop = knitr::hook_pdfcrop)
knitr
# dark gt theme
<- function(tbl){
dark_gt_theme
<- list(
style_cells cells_body(),
cells_column_labels(),
cells_column_spanners(),
cells_footnotes(),
cells_row_groups(),
cells_source_notes(),
cells_stub(),
cells_stubhead(),
cells_title()
)
<- tbl$`_summary` |>
summary_info map(
~":GRAND_SUMMARY:" %in% .x$groups
|>
) list_simplify()
if(any(summary_info)){
<- c(
style_cells
style_cells,list(
cells_grand_summary(),
cells_stub_grand_summary()
)
)
}
if(any(!(summary_info %||% T))){
<- c(
style_cells
style_cells,list(
cells_stub_summary(),
cells_summary()
)
)
}
|>
tbl opt_table_font(
font = c(
google_font(name = "Public Sans"),
default_fonts()
)|>
)tab_style(
style = "
background-color: var(--bs-body-bg);
color: var(--bs-body-color)
",
locations = style_cells
)
}
<- function(title = ""){
new_post
<- Sys.Date()
day = snakecase::to_snake_case(title, sep_out ="-")
slug
<- stringr::str_split(day, "-")[[1]]
pieces <- pieces[1]
year <- pieces[2]
month = here::here("posts", year, month)
month_path = fs::path(
post_path
year,
month,::str_glue("{day}_{slug}")
stringr
)
if(!fs::dir_exists(month_path)){
::dir_create(month_path, recurse = T)
fs
}
::new_blog_post(
quartotitle = title,
dest = post_path
) }
Prerender
prerender.py
from commonmeta import encode_doi
from pathlib import Path
import yaml
import logging
def get_all_posts(post_base:str = "posts")->list[Path]:
"""Get all post directories
Args:
post_base (str, optional):
base post path. Defaults to "posts".
Returns:
list[Path]: Path to every post
"""
= [
post_dirs
postfor year in Path(post_base).glob("*/")
for month in year.glob("*/")
for post in month.glob("*/")
]return post_dirs
def make_metadata(path:Path) -> None:
"""Create empty `_metadata.yml` file.
Args:
path (Path): Path to post
"""
= path.joinpath("_metadata.yml")
metadata_path if metadata_path.exists():
return
else:
metadata_path.touch()
def make_all_metadata(paths:list[Path]) -> None:
"""Make all `_metadata.yml`
Args:
paths (list[Path]):
List of all post paths
"""
for p in paths:
make_metadata(p)
def make_date(path:Path)->str:
"""Return a date string based on the path name
Args:
path (Path): Path to post
Returns:
(str): Date string
"""
return path.name.split("_")[0]
def make_doi() -> str:
"""Make doi number
Returns:
(str): doi
"""
= encode_doi("10.59350")
doi_url = doi_url.removeprefix("https://doi.org/")
doi_number return doi_number
def check_metadata(path:Path)->None:
"""Check and update a `_metadata.yml` file
Args:
path (Path): Path to post
"""
= path.joinpath("_metadata.yml")
metadata_path = yaml.safe_load(metadata_path.read_text())
dat
if dat is None:
= {
dat "date": make_date(path),
"doi": make_doi()
}
metadata_path.write_text(
yaml.dump(dat)
)return
# just to be safe
if not isinstance(dat, dict):
f"Non-dict _metadata for {str(path)}")
logging.warning(return
# avoid writing if not necessary
if "date" in dat \
and "doi" in dat \
and dat["date"] == make_date(path):
return
if not "doi" in dat:
"doi"] = make_doi()
dat[
if not "date" in dat:
"date"] = make_date(path)
dat[elif dat["date"] != make_date(path):
"date"] = make_date(path)
dat[
metadata_path.write_text(
yaml.dump(dat)
)
def check_all_metadata(paths: list[Path]) -> None:
"""Check and update all `_metadata.yml` files
Args:
paths (list[Path]): _description_
"""
for p in paths:
check_metadata(p)
= get_all_posts("posts")
post_dirs
make_all_metadata(post_dirs)
check_all_metadata(post_dirs)
Github Action
name: Build Site
on:
push:
branches: ["master"]
env:
RENV_PATHS_ROOT: ~/.cache/R/renv
QUARTO_PYTHON: renv/python/virtualenvs/renv-python-3.12/bin/python
jobs:
build-docs:
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: "3.12"
- name: Set Reticulate
run: |
echo "RETICULATE_PYTHON=$(which python)" >> "$GITHUB_ENV"
echo "RENV_PYTHON=$(which python)" >> "$GITHUB_ENV"
echo "QUARTO_PYTHON=$(which python)" >> "$GITHUB_ENV"
pip install -r requirements.txt - uses: r-lib/actions/setup-r@v2
- name: Cache packages
uses: actions/cache@v4
with:
path: ${{ env.RENV_PATHS_ROOT }}
key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
restore-keys: |
${{ runner.os }}-renv- - name: Restore packages
shell: Rscript {0}
run: |
if (!requireNamespace("renv", quietly = TRUE)) install.packages("renv")
renv::install("reticulate")
#reticulate::install_python("3.12:latest")
renv::use_python(type = "virtualenv")
renv::restore() - name: Set up quarto
uses: quarto-dev/quarto-actions/setup@v2
# - name: Set Quarto Python
# run: |
# echo "QUARTO_PYTHON=renv/python/virtualenvs/renv-python-3.12/bin/python" >> $GITHUB_ENV
- name: Render and publish to gh pages
uses: quarto-dev/quarto-actions/publish@v2
with:
target: gh-pages
Reuse
CC-BY 4.0