CircosHeatmap-aardio/dist/lib/r-library/ggplot2/doc/ggplot2-in-packages.html

651 lines
34 KiB
HTML
Raw Normal View History

2025-01-12 00:52:51 +08:00
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta http-equiv="X-UA-Compatible" content="IE=EDGE" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Using ggplot2 in packages</title>
<script>// Pandoc 2.9 adds attributes on both header and div. We remove the former (to
// be compatible with the behavior of Pandoc < 2.8).
document.addEventListener('DOMContentLoaded', function(e) {
var hs = document.querySelectorAll("div.section[class*='level'] > :first-child");
var i, h, a;
for (i = 0; i < hs.length; i++) {
h = hs[i];
if (!/^h[1-6]$/i.test(h.tagName)) continue; // it should be a header h1-h6
a = h.attributes;
while (a.length > 0) h.removeAttribute(a[0].name);
}
});
</script>
<style type="text/css">
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
ul.task-list{list-style: none;}
</style>
<style type="text/css">
code {
white-space: pre;
}
.sourceCode {
overflow: visible;
}
</style>
<style type="text/css" data-origin="pandoc">
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; }
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; }
code span.at { color: #7d9029; }
code span.bn { color: #40a070; }
code span.bu { color: #008000; }
code span.cf { color: #007020; font-weight: bold; }
code span.ch { color: #4070a0; }
code span.cn { color: #880000; }
code span.co { color: #60a0b0; font-style: italic; }
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; }
code span.do { color: #ba2121; font-style: italic; }
code span.dt { color: #902000; }
code span.dv { color: #40a070; }
code span.er { color: #ff0000; font-weight: bold; }
code span.ex { }
code span.fl { color: #40a070; }
code span.fu { color: #06287e; }
code span.im { color: #008000; font-weight: bold; }
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; }
code span.kw { color: #007020; font-weight: bold; }
code span.op { color: #666666; }
code span.ot { color: #007020; }
code span.pp { color: #bc7a00; }
code span.sc { color: #4070a0; }
code span.ss { color: #bb6688; }
code span.st { color: #4070a0; }
code span.va { color: #19177c; }
code span.vs { color: #4070a0; }
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; }
</style>
<script>
// apply pandoc div.sourceCode style to pre.sourceCode instead
(function() {
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
if (sheets[i].ownerNode.dataset["origin"] !== "pandoc") continue;
try { var rules = sheets[i].cssRules; } catch (e) { continue; }
var j = 0;
while (j < rules.length) {
var rule = rules[j];
// check if there is a div.sourceCode rule
if (rule.type !== rule.STYLE_RULE || rule.selectorText !== "div.sourceCode") {
j++;
continue;
}
var style = rule.style.cssText;
// check if color or background-color is set
if (rule.style.color === '' && rule.style.backgroundColor === '') {
j++;
continue;
}
// replace div.sourceCode by a pre.sourceCode rule
sheets[i].deleteRule(j);
sheets[i].insertRule('pre.sourceCode{' + style + '}', j);
}
}
})();
</script>
<style type="text/css">body {
background-color: #fff;
margin: 1em auto;
max-width: 700px;
overflow: visible;
padding-left: 2em;
padding-right: 2em;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
line-height: 1.35;
}
#TOC {
clear: both;
margin: 0 0 10px 10px;
padding: 4px;
width: 400px;
border: 1px solid #CCCCCC;
border-radius: 5px;
background-color: #f6f6f6;
font-size: 13px;
line-height: 1.3;
}
#TOC .toctitle {
font-weight: bold;
font-size: 15px;
margin-left: 5px;
}
#TOC ul {
padding-left: 40px;
margin-left: -1.5em;
margin-top: 5px;
margin-bottom: 5px;
}
#TOC ul ul {
margin-left: -2em;
}
#TOC li {
line-height: 16px;
}
table {
margin: 1em auto;
border-width: 1px;
border-color: #DDDDDD;
border-style: outset;
border-collapse: collapse;
}
table th {
border-width: 2px;
padding: 5px;
border-style: inset;
}
table td {
border-width: 1px;
border-style: inset;
line-height: 18px;
padding: 5px 5px;
}
table, table th, table td {
border-left-style: none;
border-right-style: none;
}
table thead, table tr.even {
background-color: #f7f7f7;
}
p {
margin: 0.5em 0;
}
blockquote {
background-color: #f6f6f6;
padding: 0.25em 0.75em;
}
hr {
border-style: solid;
border: none;
border-top: 1px solid #777;
margin: 28px 0;
}
dl {
margin-left: 0;
}
dl dd {
margin-bottom: 13px;
margin-left: 13px;
}
dl dt {
font-weight: bold;
}
ul {
margin-top: 0;
}
ul li {
list-style: circle outside;
}
ul ul {
margin-bottom: 0;
}
pre, code {
background-color: #f7f7f7;
border-radius: 3px;
color: #333;
white-space: pre-wrap;
}
pre {
border-radius: 3px;
margin: 5px 0px 10px 0px;
padding: 10px;
}
pre:not([class]) {
background-color: #f7f7f7;
}
code {
font-family: Consolas, Monaco, 'Courier New', monospace;
font-size: 85%;
}
p > code, li > code {
padding: 2px 0px;
}
div.figure {
text-align: center;
}
img {
background-color: #FFFFFF;
padding: 2px;
border: 1px solid #DDDDDD;
border-radius: 3px;
border: 1px solid #CCCCCC;
margin: 0 5px;
}
h1 {
margin-top: 0;
font-size: 35px;
line-height: 40px;
}
h2 {
border-bottom: 4px solid #f7f7f7;
padding-top: 10px;
padding-bottom: 2px;
font-size: 145%;
}
h3 {
border-bottom: 2px solid #f7f7f7;
padding-top: 10px;
font-size: 120%;
}
h4 {
border-bottom: 1px solid #f7f7f7;
margin-left: 8px;
font-size: 105%;
}
h5, h6 {
border-bottom: 1px solid #ccc;
font-size: 105%;
}
a {
color: #0033dd;
text-decoration: none;
}
a:hover {
color: #6666ff; }
a:visited {
color: #800080; }
a:visited:hover {
color: #BB00BB; }
a[href^="http:"] {
text-decoration: underline; }
a[href^="https:"] {
text-decoration: underline; }
code > span.kw { color: #555; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #d14; }
code > span.fl { color: #d14; }
code > span.ch { color: #d14; }
code > span.st { color: #d14; }
code > span.co { color: #888888; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #900; font-weight: bold; }
code > span.er { color: #a61717; background-color: #e3d2d2; }
</style>
</head>
<body>
<h1 class="title toc-ignore">Using ggplot2 in packages</h1>
<p>This vignette is intended for package developers who use ggplot2
within their package code. As of this writing, this includes over 2,000
packages on CRAN and many more elsewhere! Programming with ggplot2
within a package adds several constraints, particularly if you would
like to submit the package to CRAN. In particular, programming within an
R package changes the way you refer to functions from ggplot2 and how
you use ggplot2s non-standard evaluation within <code>aes()</code> and
<code>vars()</code>.</p>
<div id="referring-to-ggplot2-functions" class="section level2">
<h2>Referring to ggplot2 functions</h2>
<p>As with any function from another package, you will have to list
ggplot2 in your <code>DESCRIPTION</code> under <code>Imports</code> and
refer to its functions using <code>::</code> (e.g.,
<code>ggplot2::function_name</code>):</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb1-1"><a href="#cb1-1" tabindex="-1"></a>mpg_drv_summary <span class="ot">&lt;-</span> <span class="cf">function</span>() {</span>
<span id="cb1-2"><a href="#cb1-2" tabindex="-1"></a> ggplot2<span class="sc">::</span><span class="fu">ggplot</span>(ggplot2<span class="sc">::</span>mpg) <span class="sc">+</span> </span>
<span id="cb1-3"><a href="#cb1-3" tabindex="-1"></a> ggplot2<span class="sc">::</span><span class="fu">geom_bar</span>(ggplot2<span class="sc">::</span><span class="fu">aes</span>(<span class="at">x =</span> .data<span class="sc">$</span>drv)) <span class="sc">+</span> </span>
<span id="cb1-4"><a href="#cb1-4" tabindex="-1"></a> ggplot2<span class="sc">::</span><span class="fu">coord_flip</span>()</span>
<span id="cb1-5"><a href="#cb1-5" tabindex="-1"></a>}</span></code></pre></div>
<p>If you use ggplot2 functions frequently, you may wish to import one
or more functions from ggplot2 into your <code>NAMESPACE</code>. If you
use <a href="https://cran.r-project.org/package=roxygen2">roxygen2</a>,
you can include
<code>#&#39; @importFrom ggplot2 &lt;one or more object names&gt;</code> in
any roxygen comment block (this will not work for datasets like
<code>mpg</code>).</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb2-1"><a href="#cb2-1" tabindex="-1"></a><span class="co">#&#39; @importFrom ggplot2 ggplot aes geom_bar coord_flip</span></span>
<span id="cb2-2"><a href="#cb2-2" tabindex="-1"></a>mpg_drv_summary <span class="ot">&lt;-</span> <span class="cf">function</span>() {</span>
<span id="cb2-3"><a href="#cb2-3" tabindex="-1"></a> <span class="fu">ggplot</span>(ggplot2<span class="sc">::</span>mpg) <span class="sc">+</span> </span>
<span id="cb2-4"><a href="#cb2-4" tabindex="-1"></a> <span class="fu">geom_bar</span>(<span class="fu">aes</span>(<span class="at">x =</span> drv)) <span class="sc">+</span> </span>
<span id="cb2-5"><a href="#cb2-5" tabindex="-1"></a> <span class="fu">coord_flip</span>()</span>
<span id="cb2-6"><a href="#cb2-6" tabindex="-1"></a>}</span></code></pre></div>
<p>Even if you use many ggplot2 functions in your package, it is unwise
to use ggplot2 in <code>Depends</code> or import the entire package into
your <code>NAMESPACE</code> (e.g. with <code>#&#39; @import ggplot2</code>).
Using ggplot2 in <code>Depends</code> will attach ggplot2 when your
package is attached, which includes when your package is tested. This
makes it difficult to ensure that others can use the functions in your
package without attaching it (i.e., using <code>::</code>). Similarly,
importing all 450 of ggplot2s exported objects into your namespace
makes it difficult to separate the responsibility of your package and
the responsibility of ggplot2, in addition to making it difficult for
readers of your code to figure out where functions are coming from!</p>
</div>
<div id="using-aes-and-vars-in-a-package-function" class="section level2">
<h2>Using <code>aes()</code> and <code>vars()</code> in a package
function</h2>
<p>To create any graphic using ggplot2 you will probably need to use
<code>aes()</code> at least once. If your graphic uses facets, you might
be using <code>vars()</code> to refer to columns in the plot/layer data.
Both of these functions use non-standard evaluation, so if you try to
use them in a function within a package they will result in a CMD check
note:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb3-1"><a href="#cb3-1" tabindex="-1"></a>mpg_drv_summary <span class="ot">&lt;-</span> <span class="cf">function</span>() {</span>
<span id="cb3-2"><a href="#cb3-2" tabindex="-1"></a> <span class="fu">ggplot</span>(ggplot2<span class="sc">::</span>mpg) <span class="sc">+</span> </span>
<span id="cb3-3"><a href="#cb3-3" tabindex="-1"></a> <span class="fu">geom_bar</span>(<span class="fu">aes</span>(<span class="at">y =</span> drv)) <span class="sc">+</span> </span>
<span id="cb3-4"><a href="#cb3-4" tabindex="-1"></a> <span class="fu">facet_wrap</span>(<span class="fu">vars</span>(year))</span>
<span id="cb3-5"><a href="#cb3-5" tabindex="-1"></a>}</span></code></pre></div>
<pre><code>N checking R code for possible problems (2.7s)
mpg_drv_summary: no visible binding for global variable drv
Undefined global functions or variables:
drv</code></pre>
<p>There are three situations in which you will encounter this
problem:</p>
<ul>
<li>You already know the column name or expression in advance.</li>
<li>You have the column name as a character vector.</li>
<li>The user specifies the column name or expression, and you want your
function to use the same kind of non-standard evaluation used by
<code>aes()</code> and <code>vars()</code>.</li>
</ul>
<p>If you already know the mapping in advance (like the above example)
you should use the <code>.data</code> pronoun from <a href="https://rlang.r-lib.org/">rlang</a> to make it explicit that you
are referring to the <code>drv</code> in the layer data and not some
other variable named <code>drv</code> (which may or may not exist
elsewhere). To avoid a similar note from the CMD check about
<code>.data</code>, use <code>#&#39; @importFrom rlang .data</code> in any
roxygen code block (typically this should be in the package
documentation as generated by
<code>usethis::use_package_doc()</code>).</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb5-1"><a href="#cb5-1" tabindex="-1"></a>mpg_drv_summary <span class="ot">&lt;-</span> <span class="cf">function</span>() {</span>
<span id="cb5-2"><a href="#cb5-2" tabindex="-1"></a> <span class="fu">ggplot</span>(ggplot2<span class="sc">::</span>mpg) <span class="sc">+</span> </span>
<span id="cb5-3"><a href="#cb5-3" tabindex="-1"></a> <span class="fu">geom_bar</span>(<span class="fu">aes</span>(<span class="at">y =</span> .data<span class="sc">$</span>drv)) <span class="sc">+</span></span>
<span id="cb5-4"><a href="#cb5-4" tabindex="-1"></a> <span class="fu">facet_wrap</span>(<span class="fu">vars</span>(.data<span class="sc">$</span>year))</span>
<span id="cb5-5"><a href="#cb5-5" tabindex="-1"></a>}</span></code></pre></div>
<p>If you have the column name as a character vector (e.g.,
<code>col = &quot;drv&quot;</code>), use <code>.data[[col]]</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb6-1"><a href="#cb6-1" tabindex="-1"></a>col_summary <span class="ot">&lt;-</span> <span class="cf">function</span>(df, col, by) {</span>
<span id="cb6-2"><a href="#cb6-2" tabindex="-1"></a> <span class="fu">ggplot</span>(df) <span class="sc">+</span> </span>
<span id="cb6-3"><a href="#cb6-3" tabindex="-1"></a> <span class="fu">geom_bar</span>(<span class="fu">aes</span>(<span class="at">y =</span> .data[[col]])) <span class="sc">+</span> </span>
<span id="cb6-4"><a href="#cb6-4" tabindex="-1"></a> <span class="fu">facet_wrap</span>(<span class="fu">vars</span>(.data[[by]]))</span>
<span id="cb6-5"><a href="#cb6-5" tabindex="-1"></a>}</span>
<span id="cb6-6"><a href="#cb6-6" tabindex="-1"></a></span>
<span id="cb6-7"><a href="#cb6-7" tabindex="-1"></a><span class="fu">col_summary</span>(mpg, <span class="st">&quot;drv&quot;</span>, <span class="st">&quot;year&quot;</span>)</span></code></pre></div>
<p>If the column name or expression is supplied by the user, you can
also pass it to <code>aes()</code> or <code>vars()</code> using
<code>{{ col }}</code>. This tidy eval operator captures the expression
supplied by the user and forwards it to another tidy eval-enabled
function such as <code>aes()</code> or <code>vars()</code>.</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb7-1"><a href="#cb7-1" tabindex="-1"></a>col_summary <span class="ot">&lt;-</span> <span class="cf">function</span>(df, col, by) {</span>
<span id="cb7-2"><a href="#cb7-2" tabindex="-1"></a> <span class="fu">ggplot</span>(df) <span class="sc">+</span> </span>
<span id="cb7-3"><a href="#cb7-3" tabindex="-1"></a> <span class="fu">geom_bar</span>(<span class="fu">aes</span>(<span class="at">y =</span> {{ col }})) <span class="sc">+</span> </span>
<span id="cb7-4"><a href="#cb7-4" tabindex="-1"></a> <span class="fu">facet_wrap</span>(<span class="fu">vars</span>({{ by }}))</span>
<span id="cb7-5"><a href="#cb7-5" tabindex="-1"></a>}</span>
<span id="cb7-6"><a href="#cb7-6" tabindex="-1"></a></span>
<span id="cb7-7"><a href="#cb7-7" tabindex="-1"></a><span class="fu">col_summary</span>(mpg, drv, year)</span></code></pre></div>
<p>To summarise:</p>
<ul>
<li>If you know the mapping or facet specification is <code>col</code>
in advance, use <code>aes(.data$col)</code> or
<code>vars(.data$col)</code>.</li>
<li>If <code>col</code> is a variable that contains the column name as a
character vector, use <code>aes(.data[[col]]</code> or
<code>vars(.data[[col]])</code>.</li>
<li>If you would like the behaviour of <code>col</code> to look and feel
like it would within <code>aes()</code> and <code>vars()</code>, use
<code>aes({{ col }})</code> or <code>vars({{ col }})</code>.</li>
</ul>
<p>You will see a lot of other ways to do this in the wild, but the
syntax we use here is the only one we can guarantee will work in the
future! In particular, dont use <code>aes_()</code> or
<code>aes_string()</code>, as they are deprecated and may be removed in
a future version. Finally, dont skip the step of creating a data frame
and a mapping to pass in to <code>ggplot()</code> or its layers! You
will see other ways of doing this, but these may rely on undocumented
behaviour and can fail in unexpected ways.</p>
</div>
<div id="best-practices-for-common-tasks" class="section level2">
<h2>Best practices for common tasks</h2>
<div id="using-ggplot2-to-visualize-an-object" class="section level3">
<h3>Using ggplot2 to visualize an object</h3>
<p>ggplot2 is commonly used in packages to visualize objects (e.g., in a
<code>plot()</code>-style function). For example, a package might define
an S3 class that represents the probability of various discrete
values:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb8-1"><a href="#cb8-1" tabindex="-1"></a>mpg_drv_dist <span class="ot">&lt;-</span> <span class="fu">structure</span>(</span>
<span id="cb8-2"><a href="#cb8-2" tabindex="-1"></a> <span class="fu">c</span>(</span>
<span id="cb8-3"><a href="#cb8-3" tabindex="-1"></a> <span class="st">&quot;4&quot;</span> <span class="ot">=</span> <span class="dv">103</span> <span class="sc">/</span> <span class="dv">234</span>,</span>
<span id="cb8-4"><a href="#cb8-4" tabindex="-1"></a> <span class="st">&quot;f&quot;</span> <span class="ot">=</span> <span class="dv">106</span> <span class="sc">/</span> <span class="dv">234</span>,</span>
<span id="cb8-5"><a href="#cb8-5" tabindex="-1"></a> <span class="st">&quot;r&quot;</span> <span class="ot">=</span> <span class="dv">25</span> <span class="sc">/</span> <span class="dv">234</span></span>
<span id="cb8-6"><a href="#cb8-6" tabindex="-1"></a> ),</span>
<span id="cb8-7"><a href="#cb8-7" tabindex="-1"></a> <span class="at">class =</span> <span class="st">&quot;discrete_distr&quot;</span></span>
<span id="cb8-8"><a href="#cb8-8" tabindex="-1"></a>)</span></code></pre></div>
<p>Many S3 classes in R have a <code>plot()</code> method, but it is
unrealistic to expect that a single <code>plot()</code> method can
provide the visualization every one of your users is looking for. It is
useful, however, to provide a <code>plot()</code> method as a visual
summary that users can call to understand the essence of an object. To
satisfy all your users, we suggest writing a function that transforms
the object into a data frame (or a <code>list()</code> of data frames if
your object is more complicated). A good example of this approach is <a href="https://cran.r-project.org/package=ggdendro">ggdendro</a>, which
creates dendrograms using ggplot2 but also computes the data necessary
for users to make their own. For the above example, the function might
look like this:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb9-1"><a href="#cb9-1" tabindex="-1"></a>discrete_distr_data <span class="ot">&lt;-</span> <span class="cf">function</span>(x) {</span>
<span id="cb9-2"><a href="#cb9-2" tabindex="-1"></a> tibble<span class="sc">::</span><span class="fu">tibble</span>(</span>
<span id="cb9-3"><a href="#cb9-3" tabindex="-1"></a> <span class="at">value =</span> <span class="fu">names</span>(x),</span>
<span id="cb9-4"><a href="#cb9-4" tabindex="-1"></a> <span class="at">probability =</span> <span class="fu">as.numeric</span>(x)</span>
<span id="cb9-5"><a href="#cb9-5" tabindex="-1"></a> )</span>
<span id="cb9-6"><a href="#cb9-6" tabindex="-1"></a>}</span>
<span id="cb9-7"><a href="#cb9-7" tabindex="-1"></a></span>
<span id="cb9-8"><a href="#cb9-8" tabindex="-1"></a><span class="fu">discrete_distr_data</span>(mpg_drv_dist)</span>
<span id="cb9-9"><a href="#cb9-9" tabindex="-1"></a><span class="co">#&gt; # A tibble: 3 × 2</span></span>
<span id="cb9-10"><a href="#cb9-10" tabindex="-1"></a><span class="co">#&gt; value probability</span></span>
<span id="cb9-11"><a href="#cb9-11" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;dbl&gt;</span></span>
<span id="cb9-12"><a href="#cb9-12" tabindex="-1"></a><span class="co">#&gt; 1 4 0.440</span></span>
<span id="cb9-13"><a href="#cb9-13" tabindex="-1"></a><span class="co">#&gt; 2 f 0.453</span></span>
<span id="cb9-14"><a href="#cb9-14" tabindex="-1"></a><span class="co">#&gt; 3 r 0.107</span></span></code></pre></div>
<p>In general, users of <code>plot()</code> call it for its
side-effects: it results in a graphic being displayed. This is different
than the behaviour of a <code>ggplot()</code>, which is not displayed
unless it is explicitly <code>print()</code>ed. Because of this, ggplot2
defines its own generic <code>autoplot()</code>, a call to which is
expected to return a <code>ggplot()</code> (with no side effects).</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb10-1"><a href="#cb10-1" tabindex="-1"></a><span class="co">#&#39; @importFrom ggplot2 autoplot</span></span>
<span id="cb10-2"><a href="#cb10-2" tabindex="-1"></a>autoplot.discrete_distr <span class="ot">&lt;-</span> <span class="cf">function</span>(object, ...) {</span>
<span id="cb10-3"><a href="#cb10-3" tabindex="-1"></a> plot_data <span class="ot">&lt;-</span> <span class="fu">discrete_distr_data</span>(object)</span>
<span id="cb10-4"><a href="#cb10-4" tabindex="-1"></a> <span class="fu">ggplot</span>(plot_data, <span class="fu">aes</span>(.data<span class="sc">$</span>value, .data<span class="sc">$</span>probability)) <span class="sc">+</span></span>
<span id="cb10-5"><a href="#cb10-5" tabindex="-1"></a> <span class="fu">geom_col</span>() <span class="sc">+</span></span>
<span id="cb10-6"><a href="#cb10-6" tabindex="-1"></a> <span class="fu">coord_flip</span>() <span class="sc">+</span></span>
<span id="cb10-7"><a href="#cb10-7" tabindex="-1"></a> <span class="fu">labs</span>(<span class="at">x =</span> <span class="st">&quot;Value&quot;</span>, <span class="at">y =</span> <span class="st">&quot;Probability&quot;</span>)</span>
<span id="cb10-8"><a href="#cb10-8" tabindex="-1"></a>}</span></code></pre></div>
<p>Once an <code>autoplot()</code> method has been defined, a
<code>plot()</code> method can then consist of <code>print()</code>ing
the result of <code>autoplot()</code>:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb11-1"><a href="#cb11-1" tabindex="-1"></a><span class="co">#&#39; @importFrom graphics plot</span></span>
<span id="cb11-2"><a href="#cb11-2" tabindex="-1"></a>plot.discrete_distr <span class="ot">&lt;-</span> <span class="cf">function</span>(x, ...) {</span>
<span id="cb11-3"><a href="#cb11-3" tabindex="-1"></a> <span class="fu">print</span>(<span class="fu">autoplot</span>(x, ...))</span>
<span id="cb11-4"><a href="#cb11-4" tabindex="-1"></a>}</span></code></pre></div>
<p>It is considered bad practice to implement an S3 generic like
<code>plot()</code>, or <code>autoplot()</code> if you dont own the S3
class, as it makes it hard for the package developer who does have
control over the S3 to implement the method themselves. This shouldnt
stop you from creating your own functions to visualize these
objects!</p>
</div>
<div id="creating-a-new-theme" class="section level3">
<h3>Creating a new theme</h3>
<p>When creating a new theme, its always good practice to start with an
existing theme (e.g. <code>theme_grey()</code>) and then
<code>%+replace%</code> the elements that should be changed. This is the
right strategy even if seemingly all elements are replaced, as not doing
so makes it difficult for us to improve themes by adding new elements.
There are many excellent examples of themes in the <a href="https://cran.r-project.org/package=ggthemes">ggthemes</a>
package.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb12-1"><a href="#cb12-1" tabindex="-1"></a><span class="co">#&#39; @importFrom ggplot2 %+replace%</span></span>
<span id="cb12-2"><a href="#cb12-2" tabindex="-1"></a>theme_custom <span class="ot">&lt;-</span> <span class="cf">function</span>(...) {</span>
<span id="cb12-3"><a href="#cb12-3" tabindex="-1"></a> <span class="fu">theme_grey</span>(...) <span class="sc">%+replace%</span> </span>
<span id="cb12-4"><a href="#cb12-4" tabindex="-1"></a> <span class="fu">theme</span>(</span>
<span id="cb12-5"><a href="#cb12-5" tabindex="-1"></a> <span class="at">panel.border =</span> <span class="fu">element_rect</span>(<span class="at">linewidth =</span> <span class="dv">1</span>, <span class="at">fill =</span> <span class="cn">NA</span>),</span>
<span id="cb12-6"><a href="#cb12-6" tabindex="-1"></a> <span class="at">panel.background =</span> <span class="fu">element_blank</span>(),</span>
<span id="cb12-7"><a href="#cb12-7" tabindex="-1"></a> <span class="at">panel.grid =</span> <span class="fu">element_line</span>(<span class="at">colour =</span> <span class="st">&quot;grey80&quot;</span>)</span>
<span id="cb12-8"><a href="#cb12-8" tabindex="-1"></a> )</span>
<span id="cb12-9"><a href="#cb12-9" tabindex="-1"></a>}</span>
<span id="cb12-10"><a href="#cb12-10" tabindex="-1"></a></span>
<span id="cb12-11"><a href="#cb12-11" tabindex="-1"></a><span class="fu">mpg_drv_summary</span>() <span class="sc">+</span> <span class="fu">theme_custom</span>()</span></code></pre></div>
<p>It is important that the theme be calculated after the package is
loaded. If not, the theme object is stored in the compiled bytecode of
the built package, which may or may not align with the installed version
of ggplot2! If your package has a default theme for its visualizations,
the correct way to load it is to have a function that returns the
default theme:</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb13-1"><a href="#cb13-1" tabindex="-1"></a>default_theme <span class="ot">&lt;-</span> <span class="cf">function</span>() {</span>
<span id="cb13-2"><a href="#cb13-2" tabindex="-1"></a> <span class="fu">theme_custom</span>()</span>
<span id="cb13-3"><a href="#cb13-3" tabindex="-1"></a>}</span>
<span id="cb13-4"><a href="#cb13-4" tabindex="-1"></a></span>
<span id="cb13-5"><a href="#cb13-5" tabindex="-1"></a>mpg_drv_summary2 <span class="ot">&lt;-</span> <span class="cf">function</span>() {</span>
<span id="cb13-6"><a href="#cb13-6" tabindex="-1"></a> <span class="fu">mpg_drv_summary</span>() <span class="sc">+</span> <span class="fu">default_theme</span>()</span>
<span id="cb13-7"><a href="#cb13-7" tabindex="-1"></a>}</span></code></pre></div>
</div>
<div id="testing-ggplot2-output" class="section level3">
<h3>Testing ggplot2 output</h3>
<p>We suggest testing the output of ggplot2 in using the <a href="https://cran.r-project.org/package=vdiffr">vdiffr</a> package,
which is a tool to manage visual test cases (this is one of the ways we
test ggplot2). If changes in ggplot2 or your code introduce a change in
the visual output of a ggplot, tests will fail when you run them locally
or as part of a Continuous Integration setup. To use vdiffr, make sure
you are using <a href="https://testthat.r-lib.org/">testthat</a> (you
can use <code>usethis::use_testthat()</code> to get started) and add
vdiffr to <code>Suggests</code> in your <code>DESCRIPTION</code>. Then,
use
<code>vdiffr::expect_doppleganger(&lt;name of plot&gt;, &lt;ggplot object&gt;)</code>
to make a test that fails if there are visual changes in
<code>&lt;ggplot object&gt;</code>. However, you should consider whether
visual testing is the best strategy because it adds a dependency on how
ggplot2 performs its rendering which may change between versions. If
extracting the layer data using <code>layer_data()</code> and testing
the values directly is possible it is far better as it more directly
test the behaviour of your own code.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb14-1"><a href="#cb14-1" tabindex="-1"></a><span class="fu">test_that</span>(<span class="st">&quot;output of ggplot() is stable&quot;</span>, {</span>
<span id="cb14-2"><a href="#cb14-2" tabindex="-1"></a> vdiffr<span class="sc">::</span><span class="fu">expect_doppelganger</span>(<span class="st">&quot;A blank plot&quot;</span>, <span class="fu">ggplot</span>())</span>
<span id="cb14-3"><a href="#cb14-3" tabindex="-1"></a>})</span></code></pre></div>
</div>
<div id="ggplot2-in-suggests" class="section level3">
<h3>ggplot2 in <code>Suggests</code></h3>
<p>If you use ggplot2 in your package, most likely you will want to list
it under <code>Imports</code>. If you would like to list ggplot2 in
<code>Suggests</code> instead, you will not be able to
<code>#&#39; @importFrom ggplot2 ...</code> (i.e., you must refer to ggplot2
objects using <code>::</code>). If you use infix operators from ggplot2
like <code>%+replace%</code> and you want to keep ggplot2 in
<code>Suggests</code>, you can assign the operator within the function
before it is used:</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb15-1"><a href="#cb15-1" tabindex="-1"></a>theme_custom <span class="ot">&lt;-</span> <span class="cf">function</span>(...) {</span>
<span id="cb15-2"><a href="#cb15-2" tabindex="-1"></a> <span class="st">`</span><span class="at">%+replace%</span><span class="st">`</span> <span class="ot">&lt;-</span> ggplot2<span class="sc">::</span><span class="st">`</span><span class="at">%+replace%</span><span class="st">`</span></span>
<span id="cb15-3"><a href="#cb15-3" tabindex="-1"></a> </span>
<span id="cb15-4"><a href="#cb15-4" tabindex="-1"></a> ggplot2<span class="sc">::</span><span class="fu">theme_grey</span>(...) <span class="sc">%+replace%</span> </span>
<span id="cb15-5"><a href="#cb15-5" tabindex="-1"></a> ggplot2<span class="sc">::</span><span class="fu">theme</span>(<span class="at">panel.background =</span> ggplot2<span class="sc">::</span><span class="fu">element_blank</span>())</span>
<span id="cb15-6"><a href="#cb15-6" tabindex="-1"></a>}</span></code></pre></div>
<p>Generally, if you add a method for a ggplot2 generic like
<code>autoplot()</code>, ggplot2 should be in <code>Imports</code>. If
for some reason you would like to keep ggplot2 in <code>Suggests</code>,
it is possible to register your generics only if ggplot2 is installed
using <code>vctrs::s3_register()</code>. If you do this, you should copy
and paste the source of <code>vctrs::s3_register()</code> into your own
package to avoid adding a <a href="https://vctrs.r-lib.org/">vctrs</a>
dependency.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb16-1"><a href="#cb16-1" tabindex="-1"></a>.onLoad <span class="ot">&lt;-</span> <span class="cf">function</span>(...) {</span>
<span id="cb16-2"><a href="#cb16-2" tabindex="-1"></a> <span class="cf">if</span> (<span class="fu">requireNamespace</span>(<span class="st">&quot;ggplot2&quot;</span>, <span class="at">quietly =</span> <span class="cn">TRUE</span>)) {</span>
<span id="cb16-3"><a href="#cb16-3" tabindex="-1"></a> vctrs<span class="sc">::</span><span class="fu">s3_register</span>(<span class="st">&quot;ggplot2::autoplot&quot;</span>, <span class="st">&quot;discrete_distr&quot;</span>)</span>
<span id="cb16-4"><a href="#cb16-4" tabindex="-1"></a> }</span>
<span id="cb16-5"><a href="#cb16-5" tabindex="-1"></a>}</span></code></pre></div>
</div>
</div>
<div id="read-more" class="section level2">
<h2>Read more</h2>
<p>There are other things to consider when taking on a dependency. <a href="https://www.tidyverse.org/blog/2022/09/playing-on-the-same-team-as-your-dependecy/">This
post</a> goes into detail with many of these using ggplot2 as an example
and is a good read for anyone developing a package using ggplot2.</p>
</div>
<!-- code folding -->
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>