washr turns a cleaned dataset into a documented R data package that follows the FAIR principles, with a website, a citation file and machine readable metadata. This page walks through the workflow in the order you run it. Each step is one function, and every function is safe to run again after you have edited the files it wrote.
The FAIR Data Publishing guide covers the same steps with more explanation and the parts that happen outside R, such as creating the GitHub repository and the Zenodo release. The chapters of the guide follow the same order as the sections below.
The stable release, from CRAN:
The current development build, from the openwashdata R-universe. It is rebuilt on every push and installs like any other package, with no compiler toolchain:
The same development source from GitHub, built on your machine:
Create an R package for the dataset and open it as a project. The package name is the name of the dataset, in lower case, without dots or underscores.
Then put it under version control and on GitHub, for example with
usethis::use_git() and usethis::use_github().
The guide describes this step in detail.
setup_ci() adds the GitHub Actions workflow that runs
R CMD check on every push and pull request, on macOS,
Windows and three versions of R on Linux. The openwashdata review
standard requires it, so run it now and the package meets that part of
the standard from its first commit.
Run setup_rawdata() from the package root. It creates
data-raw/ and a processing script,
data-raw/data_processing.R, with the steps the script
should follow.
Copy the raw files into data-raw/. In the processing
script, read them, clean them into one or more tidy data frames, and end
with usethis::use_data() so each data frame lands in
data/ as an .rda file. The script also exports
each data frame as CSV and XLSX into inst/extdata/, which
is where the website and the metadata find the downloadable files.
setup_dictionary() reads every data object in
data/ and writes data-raw/dictionary.csv with
one row per variable: the file it belongs to, its name, its type, and an
empty description.
Open the CSV and write a description for every variable. The dictionary is the one place where variables are described; the roxygen documentation and the metadata are generated from it.
When the data changes later, run update_dictionary(). It
adds a row for each new variable, removes the row of a variable that no
longer exists, refreshes the types, and keeps every description and
every column you added yourself, such as unit or
allowed_values. Then run setup_roxygen()
again.
setup_roxygen() writes one file per data object under
R/, with a title and description placeholder and the
variable table from the dictionary.
Open each file, replace the title and the description, then run
devtools::document() so the help pages exist. When you
change a description in the dictionary later, run
setup_roxygen() again: it regenerates only the variable
table and keeps the title, the description and anything else you wrote
in the file.
update_description() sets the fields the openwashdata
standard expects: the language, the date, the repository URL, the bug
report URL, and the CC BY 4.0 license when the package has none yet.
Existing values are kept and merged. It also writes a few
Config/washr/ fields, such as the funding sentence and the
analytics domain of the site. The later steps read them from
DESCRIPTION, and the last section of this page explains
them.
Then open DESCRIPTION and check the title, the
description and the authors. Authors are written with
person() and carry their ORCID in the comment field. Three
more facts have no other home and go into DESCRIPTION by
hand:
X-schema.org-keywords: sanitation, faecal sludge, Kampala
X-schema.org-spatialCoverage: Kampala, Uganda
X-schema.org-temporalCoverage: 2022-03-01/2022-09-30
The keywords are a comma separated list. The spatial coverage is a place name. The temporal coverage is a start and an end date separated by a slash.
update_metadata() derives a schema.org description of
the dataset from DESCRIPTION, the dictionary, the citation
file and the files in inst/extdata, and writes it as
JSON-LD into pkgdown/templates/in-header.html. The website
build embeds it in the head of every page, where dataset search engines
read it.
The function ends with the fields it could not fill and where to fill them. Nothing is edited by hand: change the source and run it again. This function is experimental; its output shape may still change.
setup_readme() writes README.Rmd from the
openwashdata template, with the installation instructions, the download
table, and a section for the first data object. With
has_example = TRUE it adds an Example section with a
scaffold for a first plot.
Write the text, add a section for each further data object, then render it:
setup_website() writes _pkgdown.yml from
the openwashdata template and builds the site into docs/.
The template sets the Pages URL, the analytics header, the funding
sidebar, and a reference index with one entry per data object.
Running it again keeps your _pkgdown.yml and rebuilds
the site. docs/ is committed and served by GitHub Pages;
when the package deploys through a pkgdown GitHub Actions workflow
instead, the function leaves docs/ ignored.
use_brand() installs the openwashdata brand, the fonts
and colors of the site, from the latest release of the central brand
repository and wires _pkgdown.yml to it. It records the
release it installed in DESCRIPTION as
Config/washr/brand. Run it once after
setup_website(), and again after a new brand release; a run
with no new release changes nothing.
Branded PDF and Word reports about the package use the openwashdata
Quarto extension, quarto-owd, with
the formats owd-typst and owd-docx. Install it
in the package root with
quarto add openwashdata/quarto-owd; it reads the
_brand.yml that use_brand() installed, so no
second brand copy is needed. Add ^_extensions$ to
.Rbuildignore.
update_citation() writes CITATION.cff and
inst/CITATION from DESCRIPTION. Run it before
the first release so the files exist, then again with the DOI once the
release is deposited on Zenodo; the guide describes the Zenodo
steps.
Before you create the release, run
check_publication_readiness(). It reads the package and
reports, item by item, what is in place and what is missing, and for
every gap it names the step that closes it. It writes nothing, so run it
as often as you like.
After the Zenodo release, run update_citation() once
more with the DOI:
With a DOI the function also adds the DOI badge to the README and
rebuilds it and the site. A later run without the DOI keeps the DOI on
file. Run update_metadata() once more after that, so the
metadata carries the DOI as well.
The same call writes .zenodo.json from
DESCRIPTION. Zenodo reads this file when it archives a
GitHub release and takes the resource type (Dataset), the community, the
creators and the license from it. Commit the file before you create the
release. update_zenodo_json() writes it on its own.
Every function above reads what is there, merges its changes, and
writes only what changed. The two exceptions stop instead of
overwriting: setup_dictionary() when the dictionary exists
(run update_dictionary() instead, which keeps what you
wrote), and setup_readme() when README.Rmd
exists (pass force = TRUE to replace it). A full second run
of the other steps on an unchanged package changes no file.
The processing script and the README template are written for one
dataset that carries the name of the package. A package can hold more.
In data-raw/data_processing.R, repeat the export block for
each data frame, so each one is saved with
usethis::use_data() and exported to
inst/extdata/. setup_dictionary(),
setup_roxygen(), setup_website() and
update_metadata() cover every data object in
data/ on their own. setup_readme() documents
the first one, so add a section per further data object to
README.Rmd by hand.
washr ships with the openwashdata values as defaults, and every one
of them lives in DESCRIPTION, so another group publishes
with its own values by editing that file. Nothing else has to
change.
Start by naming your GitHub organisation, once:
From then on the organisation, the repository URL, the license and
the people are read from the standard DESCRIPTION fields
(URL, License, Authors@R), and
the README, the site, the citation files and the metadata follow them.
The values that have no standard field are the
Config/washr/ fields:
| Field | What it sets | Value for another group |
|---|---|---|
Config/washr/funding |
the funding sentence in the sidebar of the site | your funding sentence, Markdown allowed, or none |
Config/washr/analytics-domain |
the Plausible analytics header of the site | your Plausible domain, or none |
Config/washr/doi-provider |
the DOI badge of the README | zenodo, or the name of another provider for a generic
DOI badge |
Config/washr/zenodo-community |
the community in .zenodo.json |
your Zenodo community, or none |
Config/washr/brand-source |
the repository use_brand() copies from |
the GitHub repository of your brand, such as
yourorg/brand, or none |
Config/washr/pages-domain |
the domain of the site | only when the site is not served from
yourorg.github.io |
For a package under another organisation,
update_description() writes the funding, analytics,
community and brand fields as none and lists them, because
the openwashdata values would be wrong there. Edit them, then run the
steps as above. A field that is set is never overwritten.
check_publication_readiness() holds the package to these
values.
A license other than CC BY 4.0 is set in License before
the first update_description(), for example with
usethis::use_cc0_license() or another
usethis::use_*_license() function.
update_description() leaves a license that is set as it
is.