<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/distinguish-yourself-in-cran-person-with-orcid/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://ropensci.org/technotes/2018/10/08/orcid/"> rOpenSci - open tools for open science</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Proper identification of individuals is crucial for acknowledging and<br>
studying their scientific work, be it journal articles or pieces of<br>
software. In this tech note, one year after CRAN started supporting<br>
ORCIDs, we shall explain why and how to use unique author identifiers in<br>
DESCRIPTION files.</p>
<h2>Why use ORCIDs on CRAN?</h2>
<p>When analyzing the authorship of CRAN packages, one can look at authors’<br>
names and email addresses. Names can be written with and without quotes,<br>
email addresses change, which makes it all tricky as <a rel="nofollow" href="http://blog.revolutionanalytics.com/2018/03/the-most-prolific-package-maintainers-on-cran.html" target="_blank">noted by David<br>
Smith when he looked for the most prolific CRAN<br>
authors</a><br>
(notice our very own Scott Chamberlain and Jeroen Ooms in that<br>
scoreboard by the way?). Besides, several people can have the same name!</p>
<p>So all in all, using an unique ID per author makes sense. That’s<br>
something offered for the academic world and beyond by<br>
<a rel="nofollow" href="https://www.crossref.org/community/orcid/" target="_blank">ORCID</a>, ORCID meaning “Open<br>
Researcher and Contributor ID”. Anyone can set up an ORCID account for<br>
free and link it up to the rest of their online persona, as well as to<br>
their employment and works. When the authors of a scientific paper give<br>
their ORCID ID to the publisher, <a rel="nofollow" href="https://orcid.org/content/journal-article-display-guidelines" target="_blank">these can be included in the html and<br>
PDF versions of a<br>
paper</a>.<br>
Note that there’s no, say, <a rel="nofollow" href="https://github.com/keybase/proofs/issues/126" target="_blank">Keybase verification for<br>
ORCIDs</a>, and often the<br>
input of an ORCID ID for a paper is declarative as well. Read more about<br>
ORCID <a rel="nofollow" href="https://orcid.org/node/8" target="_blank">here</a>.</p>
<p>About one year ago, CRAN added <a rel="nofollow" href="https://twitter.com/AchimZeileis/status/917319708713668608" target="_blank">support for<br>
ORCID</a> in<br>
DESCRIPTION files by <a rel="nofollow" href="https://twitter.com/AchimZeileis/status/917660536459939840" target="_blank">a minimally invasive<br>
hack</a>. One<br>
can add the ORCID ID of an author as a <code>comment</code> field in <code>person()</code>,<br>
see e.g. <a rel="nofollow" href="https://github.com/ropensci/codemetar/blob/387456e9d62fdb9be936a089d7173e8d21d783b8/DESCRIPTION#L10" target="_blank">Carl Boettiger’s ID in <code>codemetar</code><br>
DESCRIPTION</a>,<br>
and one gets a nice little green bubble near their name on CRAN, see<br>
e.g. <a rel="nofollow" href="https://cran.r-project.org/web/packages/codemetar/index.html" target="_blank"><code>codemetar</code> CRAN<br>
page</a>.</p>
<p><img alt="screenshot of
&lt;https://cran.r-project.org/web/packages/codemetar/index.html data-recalc-dims=" src="https://i1.wp.com/ropensci.org/img/blog-images/2018-10-08-orcid/codemetar-1.png?w=456&ssl=1">&quot; /></p>
<p>The advantages of using ORCID IDs in DESCRIPTION are:</p>
<ul>
<li>
<p><strong>Unique identifiers for free!</strong> Sure, there’s no verification so<br>
someone could use your identity, but at least, it should help<br>
assigning your own work to you.</p>
</li>
<li>
<p><strong>Clickable name on CRAN pages, METACRAN pages and pkgdown<br>
websites!</strong> E.g. when clicking on Carl’s green bubble on <code>codemetar</code><br>
CRAN page, one gets to <a rel="nofollow" href="https://orcid.org/0000-0002-1642-628X" target="_blank">his ORCID<br>
profile</a> including a link to<br>
his personal website. See also <a rel="nofollow" href="https://www.r-pkg.org/pkg/codemetar" target="_blank"><code>codemetar</code> METACRAN<br>
page</a> and <a rel="nofollow" href="https://ropensci.github.io/codemetar/" target="_blank"><code>codemetar</code> pkgdown<br>
website</a>.</p>
</li>
</ul>
<p><img alt="screenshot of
&lt;https://orcid.org/0000-0002-1642-628X data-recalc-dims=" src="https://i1.wp.com/ropensci.org/img/blog-images/2018-10-08-orcid/carl-1.png?w=456&ssl=1">&quot; /></p>
<p>Even for non academics, making one’s online persona more accessible from<br>
a CRAN DESCRIPTION can’t hurt.</p>
<h2>How to manipulate ORCIDs in DESCRIPTION?</h2>
<p>So, how does one add add and interact with ORCID in DESCRIPTION? Well,<br>
thankfully, the current dev version of the RStudio <a rel="nofollow" href="https://github.com/r-lib/desc" target="_blank"><code>desc</code><br>
package</a> by <a rel="nofollow" href="https://github.com/gaborcsardi" target="_blank">Gábor<br>
Csárdi</a> has some direct support of<br>
ORCIDs! <em>Gábor too is well ranked in <a rel="nofollow" href="http://blog.revolutionanalytics.com/2018/03/the-most-prolific-package-maintainers-on-cran.html" target="_blank">the scoreboard mentioned<br>
earlier</a>!</em></p>
<pre><code>remotes::install_github(&quot;r-lib/desc&quot;)
</code></pre>
<h3>Search authors by ORCID</h3>
<p><code>desc</code> offers many functions for manipulating authors: adding or<br>
deleting them or their roles. Now you can perform these operations using<br>
ORCID to identify authors to be modified. E.g. if you want to add a role<br>
to an existing author, say Carl who worked hard enough to earn the “aut”<br>
role, you’d run</p>
<pre><code>desc::desc_add_role(role = &quot;aut&quot;,
                    orcid = &quot;0000-0002-1642-628X&quot;)
</code></pre>
<p>Obviously this very example above has probably little real-life<br>
applicability, but you could imagine manipulating DESCRIPTION files <em>en<br>
masse</em> using a table of ORCIDs and new roles.</p>
<h3>Add ORCID to authors of a package</h3>
<p>The new <code>add_orcid()</code> method and <code>desc_add_orcid()</code> functions make it<br>
possible to add ORCID IDs to authors directly instead of via the<br>
<code>comment</code> argument. So you could write some script</p>
<pre><code>desc::desc_add_orcid(&quot;0000-0002-2815-0399&quot;,
                     given = &quot;Maëlle&quot;,
                     family = &quot;Salmon&quot;)
</code></pre>
<p>and run it inside all your local package folders to add your ORCID. It<br>
will add this ORCID ID to the author whose given name is “Maëlle” and<br>
whose family name is “Salmon”. If you only write</p>
<pre><code>desc::desc_add_orcid(&quot;0000-0002-2815-0399&quot;,
                     given = &quot;Maëlle&quot;)
</code></pre>
<p>and there are two Maëlle’s, the function will error and you’ll need to<br>
run it with more specific arguments.</p>
<h3>Add all of <em>your</em> identity at once!</h3>
<p>The coolest feature of <code>desc</code> ORCID support might be that<br>
<code>desc::desc_add_me()</code> will now use the ORCID of the environment variable<br>
<code>ORCID_ID</code> if you created it. Hence, once per machine it’d now be<br>
recommended to</p>
<ul>
<li>
<p>install the <code>whoami</code> package necessary for <code>desc::desc_add_me()</code> to<br>
work. <code>install.packages(&quot;whoami&quot;)</code>.</p>
</li>
<li>
<p>create an environment variable <code>ORCID_ID</code>, editing <code>.Renviron</code> by<br>
calling e.g. <code>usethis::edit_r_environ()</code>. Here’s how the<br>
corresponding <code>.Renviron</code> line looks for me:</p>
</li>
</ul>
<pre><code>ORCID_ID=&quot;0000-0002-2815-0399&quot;
</code></pre>
<p><code>desc::desc_add_me()</code> looks for your name and email addresses in your<br>
existing configuration (git configuration, GitHub profile), see <a rel="nofollow" href="https://github.com/r-lib/whoami" target="_blank">the<br>
<code>whoami</code> package docs</a>. So say you’ve<br>
just been told to add yourself as contributor of a package you’ve<br>
improved: inside the package directory, you’d just need to run<br>
<code>desc::desc_add_me()</code> and voilà ! No risk to wrongly copy-paste your<br>
ORCID.</p>
<p>As a conclusion of this section, not only are ORCIDs useful, but they’re<br>
getting citizen status in the world of as-automatic-as-possible package<br>
development. Now, we shall see how one could use ORCIDs inside R to<br>
gather information about package authors.</p>
<h2>How to study CRAN authors via their ORCID</h2>
<p>As mentioned earlier, rOpenSci’s Scott Chamberlain is the <a rel="nofollow" href="http://blog.revolutionanalytics.com/2018/03/the-most-prolific-package-maintainers-on-cran.html" target="_blank">most prolific<br>
CRAN package<br>
maintainer</a>,<br>
so perhaps unsurprisingly, he maintains a package interacting with<br>
ORCID’s API, <a rel="nofollow" href="https://github.com/ropensci/rorcid" target="_blank"><code>rorcid</code></a>!</p>
<p>The API requires authentication so the first step after installing the<br>
package is to run:</p>
<pre><code>rorcid::orcid_auth()
</code></pre>
<p>and to save the resulting token as an <code>ORCID_TOKEN</code> environment variable<br>
in <code>.Renviron</code> (again, <code>usethis::edit_r_environ()</code> can help with that).<br>
Authentication warrants your having an ORCID account, so if you haven’t<br>
one yet, <a rel="nofollow" href="https://orcid.org/register" target="_blank">register via this link</a>.</p>
<p>Then, we’ll query all <code>comment</code>’s of <code>Authors@R</code> of CRAN packages. Some<br>
CRAN packages use the <code>Author</code> field instead, which is not recommended<br>
and doesn’t allow using <code>comment</code>.</p>
<p><em>Side-note, in general, how would one analyze stuff over the whole CRAN<br>
collection?</em></p>
<ul>
<li>
<p><em>Some information can be found in <code>tools::CRAN_package_db()</code> as seen<br>
in <a rel="nofollow" href="https://ropensci.org/technotes/2018/09/10/github-badges/" target="_blank">this recent tech<br>
note</a>.</em></p>
</li>
<li>
<p><em>There’s <a rel="nofollow" href="https://github.com/cran" target="_blank">an official read-only mirror of each all CRAN packages on<br>
GitHub</a> thanks to METACRAN.</em></p>
</li>
<li>
<p><em>METACRAN serves a <a rel="nofollow" href="https://r-pkg.org/services#crandb" target="_blank">CRAN package<br>
database</a>, wrapped by an R<br>
package of course.</em></p>
</li>
<li>
<p><em>One could try setting up a local CRAN mirror.</em></p>
</li>
</ul>
<p>Thanks to Gábor, who maintains METACRAN, for patiently answering my<br>
questions about meta-CRAN things. If we were after the comments section<br>
of just a few packages, we could query METACRAN database like so:</p>
<pre><code>url &lt;- &quot;https://crandb.r-pkg.org/-/latest?keys=[%22desc%22,%22codemetar%22]&quot;
obj  &lt;- jsonlite::fromJSON(url, simplifyVector = FALSE)
lapply(obj, function(x) eval(parse(text = x$`Authors@R`))$comment)
</code></pre>
<p>but in our case, when wanting to get all the current CRAN authors, it’s<br>
easier to use <code>tools::CRAN_package_db()</code>. As a side-note, if you find a<br>
better solution than the functions defined below <code>parse_authors()</code> and<br>
<code>parse_author()</code> (some <code>purrr</code> magic?) to coerce all authors information<br>
to a <code>data.frame</code>, feel free to comment under the post!</p>
<pre><code>library(&quot;magrittr&quot;)
all_info &lt;- tools::CRAN_package_db()
all_info &lt;- all_info[!is.na(all_info$`Authors@R`),]
all_info &lt;- all_info[, c(&quot;Package&quot;, &quot;Authors@R&quot;)]
names(all_info)[2] &lt;- &quot;authors_at_r&quot;

null_to_na &lt;- function(x){
  if(is.null(x)){
    NA
  }else{
    x
  }
}

parse_author &lt;- function(author){
  author &lt;- as.person(author)
  tibble::tibble(given = null_to_na(author$given),
                 family = null_to_na(author$family),
                 email = null_to_na(author$email),
                 comment = as.character(null_to_na(author$comment)),
                 orcid = as.character(null_to_na(author$comment[&quot;ORCID&quot;])))
}

parse_authors &lt;- function(authors_at_r){
  authors &lt;- try(eval(parse(text = authors_at_r)),
                silent = TRUE)
  if(inherits(authors, &quot;try-error&quot;)){
    return(list(NA))
  }
  
  else{
    list(purrr::map_dfr(authors, parse_author))
  }
  
}

cran_authors &lt;- all_info %>%
  as.data.frame() %>%
  dplyr::select(Package, authors_at_r) %>% 
  dplyr::rowwise() %>%
  dplyr::mutate(authors = parse_authors(authors_at_r)) %>%
  tidyr::unnest(authors)
</code></pre>
<p>This is how the resulting table looks like. Out of 13147 packages on<br>
CRAN we are looking at 5421, i.e. packages using the <code>Authors@R</code> field.<br>
There is one line per author in a package.</p>
<pre><code>str(cran_authors)
</code></pre>
<pre><code>## Classes 'tbl_df', 'tbl' and 'data.frame':    16272 obs. of  7 variables:
##  $ Package     : chr  &quot;abbyyR&quot; &quot;abc&quot; &quot;abc&quot; &quot;abc&quot; ...
##  $ authors_at_r: chr  &quot;person(\&quot;Gaurav\&quot;, \&quot;Sood\&quot;, email = \&quot;gsood07@gmail.com\&quot;, role = c(\&quot;aut\&quot;, \&quot;cre\&quot;))&quot; &quot;c( \n    person(\&quot;Csillery\&quot;, \&quot;Katalin\&quot;, role = \&quot;aut\&quot;, email=\&quot;kati.csillery@gmail.com\&quot;),\n    person(\&quot;Le&quot;| __truncated__ &quot;c( \n    person(\&quot;Csillery\&quot;, \&quot;Katalin\&quot;, role = \&quot;aut\&quot;, email=\&quot;kati.csillery@gmail.com\&quot;),\n    person(\&quot;Le&quot;| __truncated__ &quot;c( \n    person(\&quot;Csillery\&quot;, \&quot;Katalin\&quot;, role = \&quot;aut\&quot;, email=\&quot;kati.csillery@gmail.com\&quot;),\n    person(\&quot;Le&quot;| __truncated__ ...
##  $ given       : chr  &quot;Gaurav&quot; &quot;Csillery&quot; &quot;Lemaire&quot; &quot;Francois&quot; ...
##  $ family      : chr  &quot;Sood&quot; &quot;Katalin&quot; &quot;Louisiane&quot; &quot;Olivier&quot; ...
##  $ email       : chr  &quot;gsood07@gmail.com&quot; &quot;kati.csillery@gmail.com&quot; NA NA ...
##  $ comment     : chr  NA NA NA NA ...
##  $ orcid       : chr  NA NA NA NA ...
</code></pre>
<p>We can count the number of occurrences of ORCIDs.</p>
<pre><code>(cran_authors %>%
  dplyr::filter(!is.na(orcid)) %>%
  dplyr::pull(Package) %>%
  unique() %>%
  length() -> orcid_pkg_no)
</code></pre>
<pre><code>## [1] 613
</code></pre>
<p>Only 613 packages have at least an ORCID ID out of 13147 CRAN packages<br>
(you can’t have an ORCID ID without using the <code>Authors@R</code> field).</p>
<p>There are 512 unique ORCID IDs. Let’s look at the most prolific authors<br>
with an ORCID ID.</p>
<pre><code>cran_authors %>%
  dplyr::filter(!is.na(orcid)) %>%
  dplyr::count(orcid, sort = TRUE) %>%
  head(n = 10) -> most_prolific
</code></pre>
<pre><code>knitr::kable(most_prolific)
</code></pre>
<table>
<thead>
<tr>
<th align="left">orcid</th>
<th align="right">n</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">0000-0003-1444-9135</td>
<td align="right">29</td>
</tr>
<tr>
<td align="left">0000-0002-4035-0289</td>
<td align="right">21</td>
</tr>
<tr>
<td align="left">0000-0003-0918-3766</td>
<td align="right">21</td>
</tr>
<tr>
<td align="left">0000-0003-4198-9911</td>
<td align="right">19</td>
</tr>
<tr>
<td align="left">0000-0003-4097-6326</td>
<td align="right">16</td>
</tr>
<tr>
<td align="left">0000-0001-8301-0471</td>
<td align="right">13</td>
</tr>
<tr>
<td align="left">0000-0003-0645-5666</td>
<td align="right">12</td>
</tr>
<tr>
<td align="left">0000-0001-5243-233X</td>
<td align="right">11</td>
</tr>
<tr>
<td align="left">0000-0001-5670-2640</td>
<td align="right">11</td>
</tr>
<tr>
<td align="left">0000-0002-8584-459X</td>
<td align="right">10</td>
</tr>
</tbody>
</table>
<p>Then we can use <code>rorcid</code> to get a glimpse of their profile.</p>
<pre><code>rorcid::as.orcid(most_prolific$orcid)
</code></pre>
<pre><code>## [[1]]
## </code></pre>