Note: This package was generated using the litr R package, which lets you define full R packages in a single R Markdown file. For more on litr, see here.

Package setup

We start by specifying the information needed in the DESCRIPTION file of the R package.

usethis::create_package(
  path = ".",
  fields = list(
    Package = params$package_name,
    Version = "0.0.1",
    Title = "Deciding on Your Schedule for JSM",
    Description = "Navigate the JSM schedule from the comfort of an R console, get personalized recommendations for talks, and export your schedule as an ical.",
    `Authors@R` = c(
      person(
        given = "Jacob",
        family = "Bien",
        email = "jbien@usc.edu",
        role = c("aut", "cre")
        ),
      person(
        given = "Yibin",
        family = "Xiong",
        role = "ctb")
      )
    )
)
usethis::use_mit_license(copyright_holder = "J. Bien")
#' A package to help you decide what talks to attend at JSM
#'
#' We wrangled the JSM program and decades of citation and coauthorship
#' data from Semantic Scholar and Arxiv.  We have also included functionality 
#' for exporting your schedule as an ical that can be loaded into Google 
#' Calendar or similar. The result is a package that streamlines the
#' process of finding talks that you may want to attend.
#' 
#' @docType package
#' @seealso [`get_talks`], [`get_coauthors`], [`get_out_citations`], [`get_in_citations`], [`export_calendar_to_ics`], [`export_calendar_to_csv`]

Some packages we’ll be using:

library(dplyr)
library(stringr)
library(purrr)
library(lubridate)

Putting the JSM schedule into the package

We have wrangled the JSM program into a data frame, which we load here from RDS file.

load(file.path("..", "source-files", "jsm-program.Rdata"), envir = jsm <- new.env())
talks <- jsm$talks %>% 
  transmute(session_number = session_id,
            session_title = session_title,
            session_type = session_type,
            day = lubridate::date(start_time),
            start_time = start_time,
            end_time = end_time,
            author = Author %>% map_chr(~ paste(.x, collapse = ", ")),
            speaker = Presenter %>% map_chr(~ paste(.x, collapse = ", ")),
            title = talk_title,
            room = room,
            chair = Chair %>% map_chr(~ paste(.x, collapse = ", ")))

There are 3000 talks. For each talk, we provide the following information:

names(talks)
##  [1] "session_number" "session_title"  "session_type"   "day"           
##  [5] "start_time"     "end_time"       "author"         "speaker"       
##  [9] "title"          "room"           "chair"

Let’s send this off to the package:

usethis::use_data(talks)
## ✔ Adding R to 'Depends' field in DESCRIPTION.
## ✔ Creating 'data/'.
## ✔ Setting 'LazyData' to "true" in 'DESCRIPTION'.
## ✔ Saving "talks" to "data/talks.rda".
## ☐ Document your data (see <https://r-pkgs.org/data.html>).

And we’ll need to document the data set as well:

#' The JSM program as a data frame
#' 
#' @format A data frame where each row is a talk and with the following variables:
#' \describe{
#' \item{session_number}{}
#' \item{session_title}{}
#' \item{session_type}{}
#' \item{day}{The day}{}
#' \item{start_time}{}
#' \item{end_time}{}
#' \item{author}{The name(s) of the author(s).  Names separated by commas.}
#' \item{speaker}{The name of the speaker.  In rare cases where there are multiple speakers, their names are separated by commas.}
#' \item{title}{The talk title}
#' \item{room}{}
#' \item{chair}{}
#' }
#' @source This data was provided by the ASA (thank you Donna LaLonde).
"talks"
## [1] "talks"

Since this is a tibble, we’ll need to make sure our package knows how to handle tibbles:

usethis::use_tibble()
## ✔ Adding tibble to 'Imports' field in DESCRIPTION.
## ✔ Adding "@importFrom tibble tibble" to 'R/jsm2025-package.R'.
## ✔ Writing 'NAMESPACE'.
## ☐ Document a returned tibble like so:
##   #' @return a [tibble][tibble::tibble-package]

Let’s also add a character vector of words appearing in the titles:

words <- jsm$words
usethis::use_data(words)
## ✔ Saving "words" to "data/words.rda".
## ☐ Document your data (see <https://r-pkgs.org/data.html>).
#' JSM words used in titles
#' @format A character vector of 4627 JSM words from titles
#' @source From the JSM 2025 program.
"words"
## [1] "words"

Helper functions

A convenience function for filtering talks

While some users might just be happy with talks itself, we can offer some helpful functions.

#' Get talks based on some criteria
#' 
#' @param speakers character vector of speaker names.  Names start with given (first) name, following the format of JSM program.
#' @param authors character vector of author names. Same as above.
#' @param people character vector of people names.  This looks for the person as a speaker, author, and chair.
#' @param keywords character vector of words to look for in talk title
#' @param days vector of Dates (e.g. "2025-08-04")
#' @param session_types character vector, e.g. "Invited Papers"
#' @export
get_talks <- function(speakers, authors, people, keywords, days, session_types) {
  talks <- jsm2025::talks
  if (!missing(speakers)) {
    pattern <- paste(speakers, collapse = "|") %>% 
      stringr::str_replace("\\(", "\\\\(") %>% # escape parentheses in names
      stringr::str_replace("\\)", "\\\\)")
    if (!(pattern %in% c("", "NA")))
      talks <- talks %>% dplyr::filter(stringr::str_detect(.data$speaker, pattern))
  }
  if (!missing(authors)) {
    pattern <- paste(authors, collapse = "|") %>% 
      stringr::str_replace("\\(", "\\\\(") %>% # escape parentheses in names
      stringr::str_replace("\\)", "\\\\)")
    if (!(pattern %in% c("", "NA")))
      talks <- talks %>% dplyr::filter(stringr::str_detect(.data$author, pattern))
  }
  if (!missing(people)) {
    pattern <- paste(people, collapse = "|") %>% 
      stringr::str_replace("\\(", "\\\\(") %>% # escape parentheses in names
      stringr::str_replace("\\)", "\\\\)")
    if (!(pattern %in% c("", "NA")))
      talks <- talks %>% 
        dplyr::filter(
        stringr::str_detect(.data$author, pattern) |
          stringr::str_detect(.data$speaker, pattern) |
          stringr::str_detect(.data$chair, pattern)
        )
  }
  if (!missing(keywords)) {
    pattern <- paste(tolower(keywords), collapse = "|")
    if (!(pattern %in% c("", "NA")))
      talks <- talks %>% 
        dplyr::filter(stringr::str_detect(tolower(.data$title), pattern))
  }
  if (!missing(days)) {
    talks <- talks %>% dplyr::filter(.data$day %in% days)
  }
  if (!missing(session_types)) {
    pattern <- paste(tolower(session_types), collapse = "|")
    if (!(pattern %in% c("", "NA")))
      talks <- talks %>%
        dplyr::filter(stringr::str_detect(tolower(.data$session_type), pattern))
  }
  talks %>% dplyr::arrange(.data$start_time)
}

In the above we used dplyr, stringr, the magrittr pipe, and .data so let’s make sure these are properly included in the package.

usethis::use_pipe()
## ✔ Adding magrittr to 'Imports' field in DESCRIPTION.
## ✔ Writing 'R/utils-pipe.R'.
## ☐ Run `devtools::document()` to update 'NAMESPACE'.
usethis::use_package("dplyr")
## ✔ Adding dplyr to 'Imports' field in DESCRIPTION.
## ☐ Refer to functions with `dplyr::fun()`.
usethis::use_package("stringr")
## ✔ Adding stringr to 'Imports' field in DESCRIPTION.
## ☐ Refer to functions with `stringr::fun()`.
usethis::use_import_from("rlang", ".data")
## ✔ Adding rlang to 'Imports' field in DESCRIPTION.
## ✔ Adding "@importFrom rlang .data" to 'R/jsm2025-package.R'.
## ✔ Writing 'NAMESPACE'.
testthat::test_that("get_talks() works", {
  talk_rt <- get_talks(speakers = "Ryan Tibshirani")
  testthat::expect_equal(
    talk_rt$title[[1]],
    "Gradient Equilibrium in Online Learning"
  )
  sb_rt <- c("Sumanta Basu", "Ryan Tibshirani")
  testthat::expect_equal(nrow(get_talks(speakers = sb_rt)), 2)
  testthat::expect_true(
    all(
      get_talks(speakers = sb_rt)$title %in% get_talks(authors = sb_rt)$title
  ))
  testthat::expect_equal(
    nrow(get_talks(authors = "Sumanta Basu")),
    8
  )
  testthat::expect_equal(
    get_talks(speakers = "Sumanta Basu", authors = sb_rt),
    get_talks(speakers = "Sumanta Basu")
  )
  testthat::expect_equal(
    nrow(get_talks(people = "Lucas Janson")),
    7 # speaker, author, and chair
  )
})

Coauthorship and citation information

Quite a lot of work went into obtaining and processing coauthorship and citation information. We combined three sources of information:

  1. Metadata from all arxiv papers in stat.XX from January 1, 2014 to July 15, 2025 (using the arxiv bulk metadata access OAI protocol). There were 121,282 such papers.

  2. Semantic Scholar (S2)’s bulk data sets (on papers, authors, and citations), in which we started with about 200M papers and filtered down to about 400K papers (written by about 577K authors) by restricting attention to papers in statistics journals or having the arxiv stat.XX tag.

  3. The JSM 2025 program itself, along with the list of authors that was scraped from JSM 2022–2024. There are 15,406 names in total.

The S2 citation data can be thought of as a paper-cites-paper matrix. We computed from this an author-cites-author matrix. We then mapped S2 authors to JSM authors. Entity matching and fusion approaches were used to map the Arxiv and S2 author names to JSM author names. This is important and challenging since authors publish under many variations of their name (e.g. First Last, First Middle Last, F. Last, First M. Last, etc.) and since multiple people can have the same first and last name.

For the Semantic Scholar data sets we used, we acknowledge the following paper:

Waleed Ammar, Dirk Groeneveld, Chandra Bhagavatula, Iz Beltagy, Miles Crawford, Doug Downey, Jason Dunkelberger, Ahmed Elgohary, Sergey Feldman, Vu A. Ha, Rodney Michael Kinney, Sebastian Kohlmeier, Kyle Lo, Tyler C. Murray, Hsu-Han Ooi, Matthew E. Peters, Joanna L. Power, Sam Skjonsberg, Lucy Lu Wang, Christopher Wilhelm, Zheng Yuan, Madeleine van Zuylen, Oren Etzioni, “Construction of the Literature Graph in Semantic Scholar.” NAACL 2018.

library(Matrix)
authors <- readRDS(file.path("..", "source-files", "jsm_authors.RDS"))
coauthor <- readRDS(file.path("..", "source-files", "coauthorships.RDS"))
cites <- readRDS(file.path("..", "source-files", "author_cites_author.RDS"))

To make the package size as small as possible, let’s remove the redundant information before storing in the package:

stopifnot(rownames(coauthor) == authors)
stopifnot(colnames(coauthor) == authors)
stopifnot(rownames(cites) == authors)
stopifnot(colnames(cites) == authors)
rownames(coauthor) <- colnames(coauthor) <- NULL
rownames(cites) <- colnames(cites) <- NULL

Let’s send these three objects to the package:

usethis::use_data(authors)
## ✔ Saving "authors" to "data/authors.rda".
## ☐ Document your data (see <https://r-pkgs.org/data.html>).
usethis::use_data(coauthor)
## ✔ Saving "coauthor" to "data/coauthor.rda".
## ☐ Document your data (see <https://r-pkgs.org/data.html>).
usethis::use_data(cites)
## ✔ Saving "cites" to "data/cites.rda".
## ☐ Document your data (see <https://r-pkgs.org/data.html>).

We’ll need the package to know about the sparse matrix classes from the Matrix package, so let’s add it:

usethis::use_package("Matrix")
## ✔ Adding Matrix to 'Imports' field in DESCRIPTION.
## ☐ Refer to functions with `Matrix::fun()`.
# We need to import at least one function since we're not using "Matrix::": 
usethis::use_import_from("Matrix", "Matrix")
## ✔ Adding "@importFrom Matrix Matrix" to 'R/jsm2025-package.R'.
## ✔ Writing 'NAMESPACE'.
#' JSM author names
#' @format A character vector of 15,406 names from past and present JSMs
#' @source This data was from the JSM 2022-2025 programs.
"authors"
## [1] "authors"

We have a separate character vector of authors for this year’s JSM:

authors2025 <- jsm$authors_thisyear

There are 5515 authors in this year’s JSM. We will want to have precomputed recommendations available for everyone in authors. This combines everyone who has appeared on the JSM program 2022-2025. However, we want these recommendations to be about only those people who are actually giving talks in 2025. (E.g., it’s not useful to see the name of a coauthor of mine if they aren’t presenting at JSM this year!)

#' JSM 2025 author names
#' @format A character vector of 5,515 JSM 2025 author names
#' @source This data was from the JSM 2025 program.
"authors2025"
## [1] "authors2025"

Let’s send this to the package:

usethis::use_data(authors2025)
## ✔ Saving "authors2025" to "data/authors2025.rda".
## ☐ Document your data (see <https://r-pkgs.org/data.html>).
#' Coauthorship information on JSM authors
#' 
#' A coauthorship matrix.  Element `ij` gives a numerical measure of how much
#' author `authors[i]` coauthors with author `authors[j]`.  This can be roughly
#' thought of as the number of papers coauthored between this pair, even though
#' that is not strictly true.  These coauthors were computed based on
#' coauthorship information across three sources: Semantic Scholar, Arxiv, and
#' the JSM program. An approximate entity matching was performed to associate
#' names across these different data sets.  Fractional values arise when we have
#' matched a JSM author to multiple Semantic Scholar authors.
#' 
#' @format A sparse matrix of class "dgCMatrix" from the `Matrix` package.
#' @source This data was created by processing data from Arxiv, Semantic Scholar, and the JSM 2022-2025 programs.
#' 
#' Waleed Ammar, Dirk Groeneveld, Chandra Bhagavatula, Iz Beltagy, 
#' Miles Crawford, Doug Downey, Jason Dunkelberger, Ahmed Elgohary, 
#' Sergey Feldman, Vu A. Ha, Rodney Michael Kinney, Sebastian Kohlmeier, 
#' Kyle Lo, Tyler C. Murray, Hsu-Han Ooi, Matthew E. Peters, Joanna L. Power, 
#' Sam Skjonsberg, Lucy Lu Wang, Christopher Wilhelm, Zheng Yuan, 
#' Madeleine van Zuylen, Oren Etzioni, "Construction of the Literature Graph in
#' Semantic Scholar." NAACL 2018.
"coauthor"
## [1] "coauthor"
#' Citation information on JSM authors
#' 
#' A citation matrix.  Element `ij` gives a numerical measure of how much
#' author `authors[i]` cites author `authors[j]`.  This can be roughly thought 
#' of as the number of times `authors[i]` cites `authors[j]` in the literature.
#' This was based on Semantic Scholar citation data. An approximate entity matching was performed to associate names across these different data sets.
#' Fractional values arise when we have matched a JSM author to multiple 
#' Semantic Scholar authors. 
#' 
#' @format A sparse matrix of class "dgCMatrix" from the `Matrix` package.
#' @source This data was created by processing the JSM 2022-2025 programs and the "papers", "authors", and "citations" data sets from Semantic Scholar:
#'  
#' Waleed Ammar, Dirk Groeneveld, Chandra Bhagavatula, Iz Beltagy, 
#' Miles Crawford, Doug Downey, Jason Dunkelberger, Ahmed Elgohary, 
#' Sergey Feldman, Vu A. Ha, Rodney Michael Kinney, Sebastian Kohlmeier, 
#' Kyle Lo, Tyler C. Murray, Hsu-Han Ooi, Matthew E. Peters, Joanna L. Power, 
#' Sam Skjonsberg, Lucy Lu Wang, Christopher Wilhelm, Zheng Yuan, 
#' Madeleine van Zuylen, Oren Etzioni, "Construction of the Literature Graph in
#' Semantic Scholar." NAACL 2018.
"cites"
## [1] "cites"
#' Get indices of nonzero elements of a vector ordered from largest to smallest
#' 
#' This is like `which(vec != 0)`, but with indices sorted by size of `vec`.
#' 
#' @param vec a numerical vector
ordered_nz <- function(vec) {
  ii <- which(vec != 0)
  if (length(ii) == 0) return(integer(0))
  ii[order(vec[ii], decreasing = TRUE)]
}

For example:

ordered_nz(c(0, 0, 14, 0, 2, 100, -2))
## [1] 6 3 5 7
testthat::test_that("ordered_nz() works", {
  testthat::expect_equal(
    ordered_nz(c(0, 0, 14, 0, 2, 100, -2)),
    c(6, 3, 5, 7)
  )
})
## Test passed 🎊
#' Return the JSM authors who are co-authors
#' 
#' @param name name of a JSM author
#' 
#' @export
get_coauthors <- function(name) {
  ii <- which(jsm2025::authors == name)
  if (length(ii) == 0) {
    message("Author not found.")
    return(character(0))
  }
  ii_coa <- ordered_nz(jsm2025::coauthor[ii, ])
  intersect(jsm2025::authors[ii_coa], jsm2025::authors2025)
}

And let’s put in a test.

testthat::test_that("get_coauthors() works", {
  testthat::expect_true("Daniela Witten" %in% get_coauthors("Jacob Bien"))
})
#' Return the JSM authors that this JSM author cites
#' 
#' For some authors (particularly new ones), it can be useful to augment their
#' citations with those of coauthors.  Use `augment=TRUE` for this.
#' 
#' @param name name of a JSM author
#' @param augment should we include out citations of coauthors?
#' 
#' @export
get_out_citations <- function(name, augment = FALSE) {
  ii <- which(jsm2025::authors == name)
  if (length(ii) == 0) {
    message("Author not found.")
    return(character(0))
  }
  ii_cites <- ordered_nz(jsm2025::cites[ii, ])
  if (augment) {
    ii_coa <- ordered_nz(jsm2025::coauthor[ii, ])
    # weighted sum of who the coauthors cite (weighted by coauthor strength):
    wtd <- jsm2025::coauthor[ii, ii_coa] %*% jsm2025::cites[ii_coa, ]
    ii_coa_cites <- ordered_nz(as.numeric(wtd))
    # start with author's own cites and follow with those of coauthors:
    ii_cites <- c(ii_cites, setdiff(ii_coa_cites, ii_cites))
  }
  intersect(jsm2025::authors[ii_cites], jsm2025::authors2025)
}
#' Return the JSM authors that cite this JSM author
#' 
#' For some authors (particularly new ones), it can be useful to augment their
#' citations with those of coauthors.  Use `augment=TRUE` for this.
#' 
#' @param name name of a JSM author
#' @param augment should we include out citations of coauthors?
#' 
#' @export
get_in_citations <- function(name, augment = FALSE) {
  ii <- which(jsm2025::authors == name)
  if (length(ii) == 0) {
    message("Author not found.")
    return(character(0))
  }
  ii_cites <- ordered_nz(jsm2025::cites[, ii])
  if (augment) {
    ii_coa <- ordered_nz(jsm2025::coauthor[ii, ])
    # weighted sum of who cites the coauthors (weighted by coauthor strength):
    wtd <- jsm2025::coauthor[ii, ii_coa] %*% Matrix::t(jsm2025::cites[, ii_coa])
    ii_coa_cites <- ordered_nz(as.numeric(wtd))
    # start with author's own cites and follow with those of coauthors:
    ii_cites <- c(ii_cites, setdiff(ii_coa_cites, ii_cites))
  }
  intersect(jsm2025::authors[ii_cites], jsm2025::authors2025)
}

And let’s test these functions.

testthat::test_that("get_*_citations() works", {
  jb_out_cite <- get_out_citations("Jacob Bien", augment = FALSE)
  jb_in_cite <- get_in_citations("Jacob Bien", augment = FALSE)
  testthat::expect_true("Daniela Witten" %in% jb_out_cite)
  testthat::expect_true("Daniela Witten" %in% jb_in_cite)
  testthat::expect_equal(
    jb_out_cite,
    get_out_citations("Jacob Bien", augment = TRUE)[1:length(jb_out_cite)]
  )
  testthat::expect_equal(
    jb_in_cite,
    get_in_citations("Jacob Bien", augment = TRUE)[1:length(jb_in_cite)]
  )
})

Exporting for import into Google Calendar

#' Export events to a .csv format that can be imported to Google Calendar
#' 
#' This will create a .csv file that can then be imported into Google Calendar.
#' To do so, go to https://calendar.google.com/calendar/u/0/r/settings/export
#' and then click "Select file from your computer", and find the file created by
#' this function. Then choose which calendar you want these events added to and
#' click "Import."  The disadvantage of this approach is that the times (which are
#' ET) will be entered in the local time of your calendar.  So if your calendar is
#' in a different time zone when you enter these, the events will be at the wrong 
#' time.  Using `export_calendar_to_ics()` does not have this problem so is the 
#' recommended function to use rather than this one.
#' 
#' @param schedule output of a call to `get_talks()`
#' @param file filename of .csv that will be created
#' 
#' @seealso [`export_calendar_to_ics`]
#' @export
export_calendar_to_csv <- function(schedule, file = NULL) {
  schedule %>% 
    dplyr::transmute(
      Subject = paste0(.data$speaker, ": ", .data$title),
      `Start Date` = .data$day,
      `All Day Event` = FALSE,
      `Start Time` = .data$start_time,
      `End Time` = .data$end_time,
      Location = .data$room,
      Description = stringr::str_glue("Authors: {.data$author}\nSession: {.data$session_title} ({.data$session_type})\nChair: {.data$chair}; ww3.aievolution.com/JSMAnnual2025/Events/viewEv?ev={.data$session_number}")
    ) %>% 
    readr::write_csv(file)
}
usethis::use_package("readr")
## ✔ Adding readr to 'Imports' field in DESCRIPTION.
## ☐ Refer to functions with `readr::fun()`.
#' Export events to a .ics file that can be imported to Google Calendar, etc.
#' 
#' This will represent the events in the standardized iCalendar format and export
#' as a .ics file that can then be imported into most calendar apps (including 
#' Google Calendar). To do so, go to 
#' https://calendar.google.com/calendar/u/0/r/settings/export
#' and then click "Select file from your computer", and find the file created by
#' this function. Then choose which calendar you want these events added to and
#' click "Import."
#' 
#' @param schedule output of a call to `get_talks()`
#' @param file filename (should end with .ics) that will be created
#' 
#' @export
export_calendar_to_ics <- function(schedule, file = NULL) {
  if (is.null(file)) 
    file <- paste0("jsm2025-cal-", 
                   stringr::str_replace_all(Sys.time(), " ", "-"),
                   ".ics")
  cal <- schedule %>% 
    dplyr::rowwise() %>% 
    dplyr::mutate(
      event = calendar::ic_event(
        start_time = .data$start_time,
        end_time = as.numeric(difftime(time1 = .data$end_time,
                                       time2 = .data$start_time,
                                       units = "hours")),
        summary = paste0(.data$speaker, ": ", .data$title)
      )
    )
  cal$event$LOCATION <- schedule$room
  cal$event$DESCRIPTION <- stringr::str_glue_data(
    schedule, 
    "Authors: {author}\\nSession: <a href='ww3.aievolution.com/JSMAnnual2025/Events/viewEv?ev={session_number}' target='_blank'>{session_title}</a> ({session_type})\\nChair: {chair}")
  cal$event %>% 
    calendar::ic_character() %>%
    stringr::str_replace_all("^DTSTART", "DTSTART;TZID=America/Los_Angeles") %>% 
    stringr::str_replace_all("^DTEND", "DTEND;TZID=America/Los_Angeles") %>% 
    writeLines(file)
}
usethis::use_package("calendar")
## ✔ Adding calendar to 'Imports' field in DESCRIPTION.
## ☐ Refer to functions with `calendar::fun()`.

Documenting the package

We finish by running commands that will document the package.

litr::document() # <-- use instead of devtools::document()
## ℹ Updating jsm2025 documentation
## ℹ Loading jsm2025
## Writing 'NAMESPACE'
## Writing 'authors.Rd'
## Writing 'authors2025.Rd'
## Writing 'cites.Rd'
## Writing 'coauthor.Rd'
## Writing 'export_calendar_to_csv.Rd'
## Writing 'export_calendar_to_ics.Rd'
## Writing 'get_coauthors.Rd'
## Writing 'get_in_citations.Rd'
## Writing 'get_out_citations.Rd'
## Writing 'get_talks.Rd'
## Writing 'jsm2025-package.Rd'
## Writing 'ordered_nz.Rd'
## Writing 'talks.Rd'
## Writing 'pipe.Rd'
## Writing 'words.Rd'

Add README

litr::add_readme("../source-files/README.Rmd")
## ✔ Writing 'README.Rmd'.
## ✔ Adding "^README\\.Rmd$" to '.Rbuildignore'.
## ☐ Update 'README.Rmd' to include installation instructions.
## ✔ Creating '.git/hooks/'.
## ✔ Writing '.git/hooks/pre-commit'.

The README has an image, which we’ll put in the package:

if (!fs::dir_exists("man/figures")) fs::dir_create("man/figures")
fs::file_copy("../source-files/ics-imported.png", "man/figures/ics-imported.png")

Add a pkgdown site

First, let’s include the github link of our package as the URL so that we can have a link to it on our pkgdown site.

desc::desc_set(
  "URL",
  "https://github.com/jacobbien/jsm2025-project/tree/main/jsm2025"
  )
## Package: jsm2025
## Title: Deciding on Your Schedule for JSM
## Version: 0.0.1
## Authors@R (parsed):
##     * Jacob Bien <jbien@usc.edu> [aut, cre]
##     * Yibin Xiong [ctb]
## Description: Navigate the JSM schedule from the comfort of an R console,
##     get personalized recommendations for talks, and export your schedule
##     as an ical.
## License: MIT + file LICENSE
## URL: https://github.com/jacobbien/jsm2025-project/tree/main/jsm2025
## Depends:
##     R (>= 3.5)
## Imports:
##     calendar,
##     dplyr,
##     magrittr,
##     Matrix,
##     readr,
##     rlang,
##     stringr,
##     tibble
## Suggests:
##     testthat (>= 3.0.0)
## Config/testthat/edition: 3
## Encoding: UTF-8
## LazyData: true
## Roxygen: list(markdown = TRUE)
## RoxygenNote: 7.3.2

Also, let’s add a hex sticker:

add_hex_sticker("../source-files/jsm2025-hex.png")

Be sure that this next command appears after litr::document() has been called in this file.

litr::add_pkgdown("../source-files/_pkgdown.yml")
## ✔ Adding "^_pkgdown\\.yml$", "^docs$", and "^pkgdown$" to '.Rbuildignore'.
## Warning in readLines(con, warn = readLines.warn): incomplete final line found
## on './_pkgdown.yml'
## ── Installing package jsm2025 into temporary library ───────────────────────────
## ── Building pkgdown site for package jsm2025 ───────────────────────────────────
## Reading from: /Users/jacobbien/Documents/GitHub/jsm2025-project/jsm2025
## Writing to: /Users/jacobbien/Documents/GitHub/jsm2025-project/docs
## ── Sitrep ──────────────────────────────────────────────────────────────────────
## ✖ URLs not ok.
##   In _pkgdown.yml, url is missing.
##   See details in `vignette(pkgdown::metadata)`.
## ✖ Favicons not ok.
##   Found package logo but not favicons.
##   Do you need to run `build_favicons()`?
## ✔ Open graph metadata ok.
## ✔ Articles metadata ok.
## ✔ Reference metadata ok.
## ── Initialising site ───────────────────────────────────────────────────────────
## ── Building favicons ───────────────────────────────────────────────────────────
## ℹ Building favicons with <https://realfavicongenerator.net>...
## ✔ Added 'apple-touch-icon.png', 'favicon-96x96.png', 'favicon.ico',
##   'favicon.svg', 'site.webmanifest', 'web-app-manifest-192x192.png', and
##   'web-app-manifest-512x512.png'.
## ── Building home ───────────────────────────────────────────────────────────────
## Reading LICENSE.md
## Reading README.md
## Writing `404.html`
## ── Building function reference ─────────────────────────────────────────────────
## Copying man/figures/ics-imported.png to reference/figures/ics-imported.png
## Reading man/authors.Rd
## Reading man/authors2025.Rd
## Reading man/cites.Rd
## Reading man/coauthor.Rd
## Reading man/export_calendar_to_csv.Rd
## Reading man/export_calendar_to_ics.Rd
## Reading man/get_coauthors.Rd
## Reading man/get_in_citations.Rd
## Reading man/get_out_citations.Rd
## Reading man/get_talks.Rd
## Reading man/jsm2025-package.Rd
## Reading man/ordered_nz.Rd
## Reading man/pipe.Rd
## Reading man/talks.Rd
## Reading man/words.Rd
## ── Building sitemap ────────────────────────────────────────────────────────────
## ── Building search index ───────────────────────────────────────────────────────
## ── Checking for problems ───────────────────────────────────────────────────────
## ✖ Missing alt-text in 'README.md'
## • reference/figures/ics-imported.png
## ℹ Learn more in `vignette(pkgdown::accessibility)`.
## ── Finished building pkgdown site for package jsm2025 ──────────────────────────
## ── Finished building pkgdown site for package jsm2025 ──────────────────────────