rtransparency identifies and extracts indicators
of transparency from the full text of published biomedical
articles. It works on two inputs: plain TXT files (typically converted
from PDFs) and PMC XML files (the JATS XML served by PubMed Central).
For each indicator it returns whether the indicator was found and, when
found, the sentence or statement that triggered the detection.
| Indicator | What it captures | TXT | PMC XML |
|---|---|---|---|
| Conflicts of interest | A COI / competing-interests disclosure | rt_coi |
rt_coi_pmc |
| Funding | A funding / financial-support statement | rt_fund |
rt_fund_pmc |
| Protocol registration | Registration on a trial / review registry | rt_register |
rt_register_pmc |
| Novelty | Claims of novelty (“for the first time”) | rt_novelty |
rt_novelty_pmc |
| Replication | Replication / independent-validation components | rt_replication |
rt_replication_pmc |
| Data sharing | Data deposited or made openly available | rt_data_code |
rt_data_code_pmc |
| Code sharing | Source code / scripts made available | rt_data_code |
rt_data_code_pmc |
| AI-use disclosure | A statement that generative AI was (or was not) used to prepare the manuscript | rt_ai |
rt_ai_pmc |
| Open-access license | Whether the article is openly licensed, and which license | rt_oa |
rt_oa_pmc |
| Reporting guideline | Whether a reporting guideline was followed, and which one | rt_reporting |
rt_reporting_pmc |
rt_all_pmc runs all ten detectors together in a single
pass: COI, funding, registration, novelty, replication, data sharing,
code sharing, AI-use disclosure, open-access licensing and
reporting-guideline use. (rt_all covers the first five from
TXT; the others also have standalone TXT detectors, such as
rt_data_code, rt_ai, rt_oa and
rt_reporting, but are not part of the rt_all
wrapper.)
AI-use disclosure is the newest indicator. Journals have asked
authors to disclose any use of generative AI (ChatGPT and similar) in
preparing a manuscript only since 2023, so rt_ai_pmc
evaluates the indicator only for articles published in 2023 or later and
returns NA for earlier ones.
The package and its validation are described in Serghiou et al., Assessment of transparency indicators across the biomedical literature: How open is open? (PLOS Biology, 2021, doi:10.1371/journal.pbio.3001107).
PMC XML is parsed with xml2. The XML root is
standardized to the <article> node (the package
accepts the OAI-PMH, EFetch <pmc-articleset>, Europe
PMC and bare <article> shapes), default namespaces
are always stripped, and the text is split into the sections where each
indicator usually appears: acknowledgments, footnotes / author notes,
the body, the methods, the abstract and supplementary material. TXT
files are read whole and split into paragraphs.
Detection is rule-based and interpretable: each indicator is a curated set of regular expressions applied to the relevant sections, rather than a machine learning model. This keeps the output auditable (the matched statement is returned) and reproducible.
fn-type = "conflict"), from section titles
(“Conflicts of interest”, “Competing interests”, “Declaration of
interest”, “Duality of interest”), and from a set of text patterns
covering financial relationships, consulting, fees, board membership,
patents and explicit “no competing interests” declarations.
Honoraria-to-subjects and reference text are masked to reduce false
positives.<funding-group> element, from funding section titles,
and from text patterns such as “supported by”, “funded by”, “grant from
/ number”, named funders and award types. Acknowledged funding is
required to use explicit funding language (a funding verb tied to a
funder), so a bare mention of an institution or the word “support” is
not enough. No-funding declarations are excluded.NCT, PROSPERO
CRD, ISRCTN, ANZCTR ACTRN, DRKS, IRCT, UMIN,
ChiCTR) and from registration phrasing in the methods or footnotes..detect_data_code) built from public repository
facts and curated benchmark statements: field-specific accession schemes
(GEO GSE, SRA / BioProject PRJNA, PDB,
ArrayExpress, dbGaP, ProteomeXchange, Dryad / Zenodo / figshare DOIs,
…), repository URLs and names, deposit / availability /
data-availability-statement language, and supplement and file-format
signals. Crucially it distinguishes sharing (“data were
deposited in GEO”) from reuse (“data were downloaded
from GEO”) and excludes “available on request”. Code repositories
(GitHub, GitLab, Bitbucket) only count as data when paired with a data
noun, so a code-only GitHub link is not mistaken for data sharing.<license> element and its license-reference URL, and
classified to a canonical identifier (CC-BY-4.0,
CC-BY-NC-ND-4.0, CC0-1.0, …). A Creative
Commons or CC0 license (or an explicit open-access declaration) sets
is_open_access; a CC0 data-waiver is not mistaken for the
article license. This is the reuse (“R”) dimension of FAIR and feeds the
rfair
assessment.Conflict-of-interest and funding statements are detected not only in English but also in Spanish, Portuguese, French, German and Italian, using language-distinctive patterns matched on transliterated (accent-stripped) text. The German conflict-of-interest detection rate, for example, rose from 33% to 97% once these were added. The other indicators are English-only for now.
The package ships an example PMC XML file. We use it below; replace the path with your own file to analyze a different article.
rt_all_pmc returns all ten indicators in one call,
together with the matched statement text, the publication
year and article metadata.
all_indicators <- rt_all_pmc(xml_path)
dplyr::glimpse(
all_indicators[, c("pmid", "year", "is_coi_pred", "is_fund_pred",
"is_register_pred", "is_novelty_pred", "is_replication_pred",
"is_open_data", "is_open_code", "is_ai_pred",
"is_open_access", "is_reporting_pred")]
)
#> Rows: 1
#> Columns: 12
#> $ pmid <chr> "32171256"
#> $ year <int> 2020
#> $ is_coi_pred <lgl> TRUE
#> $ is_fund_pred <lgl> FALSE
#> $ is_register_pred <lgl> FALSE
#> $ is_novelty_pred <lgl> FALSE
#> $ is_replication_pred <lgl> FALSE
#> $ is_open_data <lgl> TRUE
#> $ is_open_code <lgl> FALSE
#> $ is_ai_pred <lgl> NA
#> $ is_open_access <lgl> TRUE
#> $ is_reporting_pred <lgl> FALSEis_ai_pred is NA here because this example
article predates 2023; for a 2023 or later article it would be
TRUE or FALSE.
coi <- rt_coi_pmc(xml_path)
c(is_coi = coi$is_coi_pred, text = substr(coi$coi_text, 1, 120))
#> is_coi
#> "TRUE"
#> text
#> "Competing interests In the past 36 months, J.D.W. received research support through the Collaboration for Research Integ"rt_all_pmc already reports is_open_data and
is_open_code; rt_data_code_pmc is the focused
view that also returns the matched statements. Detection is native and
needs no external packages.
data_code <- rt_data_code_pmc(xml_path)
dplyr::glimpse(
data_code[, c("is_open_data", "open_data_statements",
"is_open_code", "open_code_statements")]
)
#> Rows: 1
#> Columns: 4
#> $ is_open_data <lgl> TRUE
#> $ open_data_statements <chr> "Availability of data and materialsData will be s…
#> $ is_open_code <lgl> FALSE
#> $ open_code_statements <chr> ""rt_all_pmc and rt_data_code_pmc also return
open_data_links and open_code_links: the
repository and accession URLs extracted from the statements, ready to
pass to FAIR-assessment tooling such as rfair. Article
metadata (title, journal, identifiers, dates) is available separately
via rt_meta_pmc.
The plain-text detectors take either a file path or the text itself,
and return the same indicator columns as the XML detectors.
rt_all_pdf() scores a PDF in one call (it needs the poppler
pdftotext utility). The chunks below are illustrative and
are not executed when the vignette is built.
pdf_path <- system.file(
"extdata", "PMID32171256-PMC7071725.pdf", package = "rtransparency"
)
rt_all_pdf(pdf_path) # all ten indicators from a PDF
article <- rt_read_pdf(pdf_path) # or extract the text once ...
rt_coi(text = article) # ... and run any detector on it
rt_all(text = article)
rt_all("article.txt") # a text file works the same way
rt_all_txt_dir("path/to/articles") # a directory of TXT and PDF filesrt_ai is the plain-text counterpart of
rt_ai_pmc. A text file carries no reliable publication
date, so rt_ai applies no 2023 year gate
(is_ai_pred is always TRUE or
FALSE, never NA) and cannot confine the scan
to back-matter sections the way the XML detector does. Restrict it to
articles published in 2023 or later, and expect a slightly higher
false-positive rate on papers that use AI as a research method.
rt_all_pmc_dir() runs all ten indicators over an entire
directory (or a vector of file paths) in one call, designed for
corpus-scale analysis.
# Sequential, in memory
res <- rt_all_pmc_dir("path/to/xml")
# Resumable and parallel: results are written to a CSV in chunks, a re-run skips
# files already recorded, and a malformed file yields an is_success = FALSE row
# instead of aborting the run.
future::plan("multisession")
res <- rt_all_pmc_dir(
"path/to/xml", output = "results.csv", parallel = TRUE
)With one row per article, rt_summary() reports
per-indicator prevalence with a Wilson confidence interval and a
sensitivity/specificity-corrected (Rogan-Gladen) prevalence;
rt_score() adds a per-article count of openness practices;
and rt_plot() draws prevalence bars and yearly trends. The
transparency-summary vignette covers this in depth.
data(rt_demo) # a small simulated example shipped with the package
rt_summary(rt_demo)[, c("indicator", "percent", "adj_percent")]
#> # A tibble: 10 × 3
#> indicator percent adj_percent
#> <chr> <dbl> <dbl>
#> 1 is_coi_pred 70.4 74.9
#> 2 is_fund_pred 79.6 86.1
#> 3 is_register_pred 29.7 24.6
#> 4 is_open_data 20.4 25.7
#> 5 is_open_code 8.5 9.13
#> 6 is_novelty_pred 54.4 62.8
#> 7 is_replication_pred 9.42 8.25
#> 8 is_ai_pred 25.2 NA
#> 9 is_open_access 82.2 NA
#> 10 is_reporting_pred 13.9 13.7rt_fetch_pmc() downloads full-text XML for PMCIDs,
PubMed IDs or DOIs from NCBI (or Europe PMC with
source = "europepmc"), reusing files already downloaded and
reporting which articles have a full-text body.
rt_convert_ids() maps between the identifier types.
A few functions go further than detecting whether a statement exists:
rt_authors_pmc() and rt_funders_pmc() read
tagged JATS metadata: ORCID coverage and CRediT contribution roles, and
funders with their Crossref Funder Registry and ROR identifiers and
award numbers.rt_trial_ids() extracts registry identifiers from the
registration text, and rt_registration_timing() asks
ClinicalTrials.gov whether each trial was registered before it
started.rt_fill_coi_pubmed() recovers conflict-of-interest
statements that PubMed records but the full-text XML lacks.rt_check_links() checks whether the data and code links
a statement gives actually resolve.rt_ethics_pmc() and rt_ethics() detect
ethics approval and informed consent statements. They are experimental:
not yet validated against hand labels, so they are kept out of
rt_all_pmc().Every indicator is benchmarked against hand labels; the current
numbers, their provenance and the scripts that reproduce them are in
inst/benchmark/ and data-raw/benchmark/ of the
source repository, and the README summarizes them. The accuracy table
rt_accuracy used by rt_summary() records each
estimate with its validation counts, so the corrected prevalence carries
the uncertainty of the validation.
Functions that operate on TXT files do not end in _pmc;
functions that operate on PMC XML end in _pmc. Data and
code detection is implemented natively and no longer requires the
oddpub or tokenizers packages.