2025-01-12 04:36:52 +08:00

679 lines
42 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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" />
<meta name="author" content="Kirill Müller, Hadley Wickham" />
<title>Printing vectors nicely in tibbles</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 { 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">Printing vectors nicely in tibbles</h1>
<h4 class="author">Kirill Müller, Hadley Wickham</h4>
<p>You can get basic control over how a vector is printed in a tibble by
providing a <code>format()</code> method. If you want greater control,
you need to understand how printing works. The presentation of a column
in a tibble is controlled by two S3 generics:</p>
<ul>
<li><code>vctrs::vec_ptype_abbr()</code> determines what goes into the
column header.</li>
<li><code>pillar::pillar_shaft()</code> determines what goes into the
body, or the shaft, of the column.</li>
</ul>
<p>Technically a <a href="https://en.wikipedia.org/wiki/Column#Nomenclature"><em>pillar</em></a>
is composed of a <em>shaft</em> (decorated with an <em>ornament</em>),
with a <em>capital</em> above and a <em>base</em> below. Multiple
pillars form a <em>colonnade</em>, which can be stacked in multiple
<em>tiers</em>. This is the motivation behind the names in our API.</p>
<p>This short vignette shows the basics of column styling using a
<code>&quot;latlon&quot;</code> vector. The vignette imagines the code is in a
package, so that you can see the roxygen2 commands youll need to create
documentation and the <code>NAMESPACE</code> file. In this vignette,
well attach pillar and vctrs:</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><span class="fu">library</span>(vctrs)</span>
<span id="cb1-2"><a href="#cb1-2" tabindex="-1"></a><span class="fu">library</span>(pillar)</span></code></pre></div>
<p>You dont need to do this in a package. Instead, youll need to
<em>import</em> the packages by then to the <code>Imports:</code>
section of your <code>DESCRIPTION</code>. The following helper does this
for you:</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>usethis<span class="sc">::</span><span class="fu">use_package</span>(<span class="st">&quot;vctrs&quot;</span>)</span>
<span id="cb2-2"><a href="#cb2-2" tabindex="-1"></a>usethis<span class="sc">::</span><span class="fu">use_package</span>(<span class="st">&quot;pillar&quot;</span>)</span></code></pre></div>
<div id="prerequisites" class="section level2">
<h2>Prerequisites</h2>
<p>To illustrate the basic ideas were going to create a
<code>&quot;latlon&quot;</code> class that encodes geographic coordinates in a
record. Well pretend that this code lives in a package called earth.
For simplicity, the values are printed as degrees and minutes only. By
using <code>vctrs_rcrd()</code>, we already get the infrastructure to
make this class fully compatible with data frames for free. See
<code>vignette(&quot;s3-vector&quot;, package = &quot;vctrs&quot;)</code> for details on the
record data type.</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><span class="co">#&#39; @export</span></span>
<span id="cb3-2"><a href="#cb3-2" tabindex="-1"></a>latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(lat, lon) {</span>
<span id="cb3-3"><a href="#cb3-3" tabindex="-1"></a> <span class="fu">new_rcrd</span>(<span class="fu">list</span>(<span class="at">lat =</span> lat, <span class="at">lon =</span> lon), <span class="at">class =</span> <span class="st">&quot;earth_latlon&quot;</span>)</span>
<span id="cb3-4"><a href="#cb3-4" tabindex="-1"></a>}</span>
<span id="cb3-5"><a href="#cb3-5" tabindex="-1"></a></span>
<span id="cb3-6"><a href="#cb3-6" tabindex="-1"></a><span class="co">#&#39; @export</span></span>
<span id="cb3-7"><a href="#cb3-7" tabindex="-1"></a>format.earth_latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(x, ..., <span class="at">formatter =</span> deg_min) {</span>
<span id="cb3-8"><a href="#cb3-8" tabindex="-1"></a> x_valid <span class="ot">&lt;-</span> <span class="fu">which</span>(<span class="sc">!</span><span class="fu">is.na</span>(x))</span>
<span id="cb3-9"><a href="#cb3-9" tabindex="-1"></a></span>
<span id="cb3-10"><a href="#cb3-10" tabindex="-1"></a> lat <span class="ot">&lt;-</span> <span class="fu">field</span>(x, <span class="st">&quot;lat&quot;</span>)[x_valid]</span>
<span id="cb3-11"><a href="#cb3-11" tabindex="-1"></a> lon <span class="ot">&lt;-</span> <span class="fu">field</span>(x, <span class="st">&quot;lon&quot;</span>)[x_valid]</span>
<span id="cb3-12"><a href="#cb3-12" tabindex="-1"></a></span>
<span id="cb3-13"><a href="#cb3-13" tabindex="-1"></a> ret <span class="ot">&lt;-</span> <span class="fu">rep</span>(<span class="cn">NA_character_</span>, <span class="fu">vec_size</span>(x))</span>
<span id="cb3-14"><a href="#cb3-14" tabindex="-1"></a> ret[x_valid] <span class="ot">&lt;-</span> <span class="fu">paste0</span>(<span class="fu">formatter</span>(lat, <span class="st">&quot;lat&quot;</span>), <span class="st">&quot; &quot;</span>, <span class="fu">formatter</span>(lon, <span class="st">&quot;lon&quot;</span>))</span>
<span id="cb3-15"><a href="#cb3-15" tabindex="-1"></a> <span class="co"># It&#39;s important to keep NA in the vector!</span></span>
<span id="cb3-16"><a href="#cb3-16" tabindex="-1"></a> ret</span>
<span id="cb3-17"><a href="#cb3-17" tabindex="-1"></a>}</span>
<span id="cb3-18"><a href="#cb3-18" tabindex="-1"></a></span>
<span id="cb3-19"><a href="#cb3-19" tabindex="-1"></a>deg_min <span class="ot">&lt;-</span> <span class="cf">function</span>(x, direction) {</span>
<span id="cb3-20"><a href="#cb3-20" tabindex="-1"></a> pm <span class="ot">&lt;-</span> <span class="cf">if</span> (direction <span class="sc">==</span> <span class="st">&quot;lat&quot;</span>) <span class="fu">c</span>(<span class="st">&quot;N&quot;</span>, <span class="st">&quot;S&quot;</span>) <span class="cf">else</span> <span class="fu">c</span>(<span class="st">&quot;E&quot;</span>, <span class="st">&quot;W&quot;</span>)</span>
<span id="cb3-21"><a href="#cb3-21" tabindex="-1"></a></span>
<span id="cb3-22"><a href="#cb3-22" tabindex="-1"></a> sign <span class="ot">&lt;-</span> <span class="fu">sign</span>(x)</span>
<span id="cb3-23"><a href="#cb3-23" tabindex="-1"></a> x <span class="ot">&lt;-</span> <span class="fu">abs</span>(x)</span>
<span id="cb3-24"><a href="#cb3-24" tabindex="-1"></a> deg <span class="ot">&lt;-</span> <span class="fu">trunc</span>(x)</span>
<span id="cb3-25"><a href="#cb3-25" tabindex="-1"></a> x <span class="ot">&lt;-</span> x <span class="sc">-</span> deg</span>
<span id="cb3-26"><a href="#cb3-26" tabindex="-1"></a> min <span class="ot">&lt;-</span> <span class="fu">round</span>(x <span class="sc">*</span> <span class="dv">60</span>)</span>
<span id="cb3-27"><a href="#cb3-27" tabindex="-1"></a></span>
<span id="cb3-28"><a href="#cb3-28" tabindex="-1"></a> <span class="co"># Ensure the columns are always the same width so they line up nicely</span></span>
<span id="cb3-29"><a href="#cb3-29" tabindex="-1"></a> ret <span class="ot">&lt;-</span> <span class="fu">sprintf</span>(<span class="st">&quot;%d°%.2d&#39;%s&quot;</span>, deg, min, <span class="fu">ifelse</span>(sign <span class="sc">&gt;=</span> <span class="dv">0</span>, pm[[<span class="dv">1</span>]], pm[[<span class="dv">2</span>]]))</span>
<span id="cb3-30"><a href="#cb3-30" tabindex="-1"></a> <span class="fu">format</span>(ret, <span class="at">justify =</span> <span class="st">&quot;right&quot;</span>)</span>
<span id="cb3-31"><a href="#cb3-31" tabindex="-1"></a>}</span>
<span id="cb3-32"><a href="#cb3-32" tabindex="-1"></a></span>
<span id="cb3-33"><a href="#cb3-33" tabindex="-1"></a><span class="fu">latlon</span>(<span class="fu">c</span>(<span class="fl">32.71</span>, <span class="fl">2.95</span>), <span class="fu">c</span>(<span class="sc">-</span><span class="fl">117.17</span>, <span class="fl">1.67</span>))</span>
<span id="cb3-34"><a href="#cb3-34" tabindex="-1"></a><span class="co">#&gt; &lt;earth_latlon[2]&gt;</span></span>
<span id="cb3-35"><a href="#cb3-35" tabindex="-1"></a><span class="co">#&gt; [1] 32°43&#39;N 117°10&#39;W 2°57&#39;N 1°40&#39;E</span></span></code></pre></div>
</div>
<div id="using-in-a-tibble" class="section level2">
<h2>Using in a tibble</h2>
<p>Columns of this class can be used in a tibble right away because
weve made a class using the vctrs infrastructure and have provided a
<code>format()</code> method:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode r"><code class="sourceCode r"><span id="cb4-1"><a href="#cb4-1" tabindex="-1"></a><span class="fu">library</span>(tibble)</span>
<span id="cb4-2"><a href="#cb4-2" tabindex="-1"></a><span class="co">#&gt; </span></span>
<span id="cb4-3"><a href="#cb4-3" tabindex="-1"></a><span class="co">#&gt; Attaching package: &#39;tibble&#39;</span></span>
<span id="cb4-4"><a href="#cb4-4" tabindex="-1"></a><span class="co">#&gt; The following object is masked from &#39;package:vctrs&#39;:</span></span>
<span id="cb4-5"><a href="#cb4-5" tabindex="-1"></a><span class="co">#&gt; </span></span>
<span id="cb4-6"><a href="#cb4-6" tabindex="-1"></a><span class="co">#&gt; data_frame</span></span>
<span id="cb4-7"><a href="#cb4-7" tabindex="-1"></a></span>
<span id="cb4-8"><a href="#cb4-8" tabindex="-1"></a>loc <span class="ot">&lt;-</span> <span class="fu">latlon</span>(</span>
<span id="cb4-9"><a href="#cb4-9" tabindex="-1"></a> <span class="fu">c</span>(<span class="fl">28.3411783</span>, <span class="fl">32.7102978</span>, <span class="fl">30.2622356</span>, <span class="fl">37.7859102</span>, <span class="fl">28.5</span>, <span class="cn">NA</span>),</span>
<span id="cb4-10"><a href="#cb4-10" tabindex="-1"></a> <span class="fu">c</span>(<span class="sc">-</span><span class="fl">81.5480348</span>, <span class="sc">-</span><span class="fl">117.1704058</span>, <span class="sc">-</span><span class="fl">97.7403327</span>, <span class="sc">-</span><span class="fl">122.4131357</span>, <span class="sc">-</span><span class="fl">81.4</span>, <span class="cn">NA</span>)</span>
<span id="cb4-11"><a href="#cb4-11" tabindex="-1"></a>)</span>
<span id="cb4-12"><a href="#cb4-12" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" tabindex="-1"></a>data <span class="ot">&lt;-</span> <span class="fu">tibble</span>(<span class="at">venue =</span> <span class="st">&quot;rstudio::conf&quot;</span>, <span class="at">year =</span> <span class="dv">2017</span><span class="sc">:</span><span class="dv">2022</span>, <span class="at">loc =</span> loc)</span>
<span id="cb4-14"><a href="#cb4-14" tabindex="-1"></a></span>
<span id="cb4-15"><a href="#cb4-15" tabindex="-1"></a>data</span>
<span id="cb4-16"><a href="#cb4-16" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb4-17"><a href="#cb4-17" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb4-18"><a href="#cb4-18" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;erth_ltl&gt;</span></span>
<span id="cb4-19"><a href="#cb4-19" tabindex="-1"></a><span class="co">#&gt; 1 rstudio::conf 2017 28°20&#39;N 81°33&#39;W</span></span>
<span id="cb4-20"><a href="#cb4-20" tabindex="-1"></a><span class="co">#&gt; 2 rstudio::conf 2018 32°43&#39;N 117°10&#39;W</span></span>
<span id="cb4-21"><a href="#cb4-21" tabindex="-1"></a><span class="co">#&gt; 3 rstudio::conf 2019 30°16&#39;N 97°44&#39;W</span></span>
<span id="cb4-22"><a href="#cb4-22" tabindex="-1"></a><span class="co">#&gt; 4 rstudio::conf 2020 37°47&#39;N 122°25&#39;W</span></span>
<span id="cb4-23"><a href="#cb4-23" tabindex="-1"></a><span class="co">#&gt; 5 rstudio::conf 2021 28°30&#39;N 81°24&#39;W</span></span>
<span id="cb4-24"><a href="#cb4-24" tabindex="-1"></a><span class="co">#&gt; 6 rstudio::conf 2022 NA</span></span></code></pre></div>
<p>This output is ok, but we could improve it by:</p>
<ol style="list-style-type: decimal">
<li><p>Using a more description type abbreviation than
<code>&lt;erth_ltl&gt;</code>.</p></li>
<li><p>Using a dash of colour to highlight the most important parts of
the value.</p></li>
<li><p>Providing a narrower view when horizontal space is at a
premium.</p></li>
</ol>
<p>The following sections show how to enhance the rendering.</p>
</div>
<div id="fixing-the-data-type" class="section level2">
<h2>Fixing the data type</h2>
<p>Instead of <code>&lt;erth_ltl&gt;</code> wed prefer to use
<code>&lt;latlon&gt;</code>. We can do that by implementing the
<code>vec_ptype_abbr()</code> method, which should return a string that
can be used in a column header. For your own classes, strive for an
evocative abbreviation thats under 6 characters.</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><span class="co">#&#39; @export</span></span>
<span id="cb5-2"><a href="#cb5-2" tabindex="-1"></a>vec_ptype_abbr.earth_latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(x) {</span>
<span id="cb5-3"><a href="#cb5-3" tabindex="-1"></a> <span class="st">&quot;latlon&quot;</span></span>
<span id="cb5-4"><a href="#cb5-4" tabindex="-1"></a>}</span>
<span id="cb5-5"><a href="#cb5-5" tabindex="-1"></a></span>
<span id="cb5-6"><a href="#cb5-6" tabindex="-1"></a>data</span>
<span id="cb5-7"><a href="#cb5-7" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb5-8"><a href="#cb5-8" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb5-9"><a href="#cb5-9" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;latlon&gt;</span></span>
<span id="cb5-10"><a href="#cb5-10" tabindex="-1"></a><span class="co">#&gt; 1 rstudio::conf 2017 28°20&#39;N 81°33&#39;W</span></span>
<span id="cb5-11"><a href="#cb5-11" tabindex="-1"></a><span class="co">#&gt; 2 rstudio::conf 2018 32°43&#39;N 117°10&#39;W</span></span>
<span id="cb5-12"><a href="#cb5-12" tabindex="-1"></a><span class="co">#&gt; 3 rstudio::conf 2019 30°16&#39;N 97°44&#39;W</span></span>
<span id="cb5-13"><a href="#cb5-13" tabindex="-1"></a><span class="co">#&gt; 4 rstudio::conf 2020 37°47&#39;N 122°25&#39;W</span></span>
<span id="cb5-14"><a href="#cb5-14" tabindex="-1"></a><span class="co">#&gt; 5 rstudio::conf 2021 28°30&#39;N 81°24&#39;W</span></span>
<span id="cb5-15"><a href="#cb5-15" tabindex="-1"></a><span class="co">#&gt; 6 rstudio::conf 2022 NA</span></span></code></pre></div>
</div>
<div id="custom-rendering" class="section level2">
<h2>Custom rendering</h2>
<p>The <code>format()</code> method is used by default for rendering.
For custom formatting you need to implement the
<code>pillar_shaft()</code> method. This function should always return a
pillar shaft object, created by <code>new_pillar_shaft_simple()</code>
or similar. <code>new_pillar_shaft_simple()</code> accepts ANSI escape
codes for colouring, and pillar includes some built in styles like
<code>style_subtle()</code>. We can use subtle style for the degree and
minute separators to make the data more obvious.</p>
<p>First we define a degree formatter that makes use of
<code>style_subtle()</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>deg_min_color <span class="ot">&lt;-</span> <span class="cf">function</span>(x, direction) {</span>
<span id="cb6-2"><a href="#cb6-2" tabindex="-1"></a> pm <span class="ot">&lt;-</span> <span class="cf">if</span> (direction <span class="sc">==</span> <span class="st">&quot;lat&quot;</span>) <span class="fu">c</span>(<span class="st">&quot;N&quot;</span>, <span class="st">&quot;S&quot;</span>) <span class="cf">else</span> <span class="fu">c</span>(<span class="st">&quot;E&quot;</span>, <span class="st">&quot;W&quot;</span>)</span>
<span id="cb6-3"><a href="#cb6-3" tabindex="-1"></a></span>
<span id="cb6-4"><a href="#cb6-4" tabindex="-1"></a> sign <span class="ot">&lt;-</span> <span class="fu">sign</span>(x)</span>
<span id="cb6-5"><a href="#cb6-5" tabindex="-1"></a> x <span class="ot">&lt;-</span> <span class="fu">abs</span>(x)</span>
<span id="cb6-6"><a href="#cb6-6" tabindex="-1"></a> deg <span class="ot">&lt;-</span> <span class="fu">trunc</span>(x)</span>
<span id="cb6-7"><a href="#cb6-7" tabindex="-1"></a> x <span class="ot">&lt;-</span> x <span class="sc">-</span> deg</span>
<span id="cb6-8"><a href="#cb6-8" tabindex="-1"></a> rad <span class="ot">&lt;-</span> <span class="fu">round</span>(x <span class="sc">*</span> <span class="dv">60</span>)</span>
<span id="cb6-9"><a href="#cb6-9" tabindex="-1"></a> ret <span class="ot">&lt;-</span> <span class="fu">sprintf</span>(</span>
<span id="cb6-10"><a href="#cb6-10" tabindex="-1"></a> <span class="st">&quot;%d%s%.2d%s%s&quot;</span>,</span>
<span id="cb6-11"><a href="#cb6-11" tabindex="-1"></a> deg,</span>
<span id="cb6-12"><a href="#cb6-12" tabindex="-1"></a> pillar<span class="sc">::</span><span class="fu">style_subtle</span>(<span class="st">&quot;°&quot;</span>),</span>
<span id="cb6-13"><a href="#cb6-13" tabindex="-1"></a> rad,</span>
<span id="cb6-14"><a href="#cb6-14" tabindex="-1"></a> pillar<span class="sc">::</span><span class="fu">style_subtle</span>(<span class="st">&quot;&#39;&quot;</span>),</span>
<span id="cb6-15"><a href="#cb6-15" tabindex="-1"></a> pm[<span class="fu">ifelse</span>(sign <span class="sc">&gt;=</span> <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>)]</span>
<span id="cb6-16"><a href="#cb6-16" tabindex="-1"></a> )</span>
<span id="cb6-17"><a href="#cb6-17" tabindex="-1"></a> <span class="fu">format</span>(ret, <span class="at">justify =</span> <span class="st">&quot;right&quot;</span>)</span>
<span id="cb6-18"><a href="#cb6-18" tabindex="-1"></a>}</span></code></pre></div>
<p>And then we pass that to our <code>format()</code> method:</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><span class="co">#&#39; @importFrom pillar pillar_shaft</span></span>
<span id="cb7-2"><a href="#cb7-2" tabindex="-1"></a><span class="co">#&#39; @export</span></span>
<span id="cb7-3"><a href="#cb7-3" tabindex="-1"></a>pillar_shaft.earth_latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(x, ...) {</span>
<span id="cb7-4"><a href="#cb7-4" tabindex="-1"></a> out <span class="ot">&lt;-</span> <span class="fu">format</span>(x, <span class="at">formatter =</span> deg_min_color)</span>
<span id="cb7-5"><a href="#cb7-5" tabindex="-1"></a> pillar<span class="sc">::</span><span class="fu">new_pillar_shaft_simple</span>(out, <span class="at">align =</span> <span class="st">&quot;right&quot;</span>)</span>
<span id="cb7-6"><a href="#cb7-6" tabindex="-1"></a>}</span></code></pre></div>
<p>Currently, ANSI escapes are not rendered in vignettes, so this result
doesnt look any different, but if you run the code yourself youll see
an improved display.</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>data</span>
<span id="cb8-2"><a href="#cb8-2" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb8-3"><a href="#cb8-3" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb8-4"><a href="#cb8-4" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;latlon&gt;</span></span>
<span id="cb8-5"><a href="#cb8-5" tabindex="-1"></a><span class="co">#&gt; 1 rstudio::conf 2017 28°20&#39;N 81°33&#39;W</span></span>
<span id="cb8-6"><a href="#cb8-6" tabindex="-1"></a><span class="co">#&gt; 2 rstudio::conf 2018 32°43&#39;N 117°10&#39;W</span></span>
<span id="cb8-7"><a href="#cb8-7" tabindex="-1"></a><span class="co">#&gt; 3 rstudio::conf 2019 30°16&#39;N 97°44&#39;W</span></span>
<span id="cb8-8"><a href="#cb8-8" tabindex="-1"></a><span class="co">#&gt; 4 rstudio::conf 2020 37°47&#39;N 122°25&#39;W</span></span>
<span id="cb8-9"><a href="#cb8-9" tabindex="-1"></a><span class="co">#&gt; 5 rstudio::conf 2021 28°30&#39;N 81°24&#39;W</span></span>
<span id="cb8-10"><a href="#cb8-10" tabindex="-1"></a><span class="co">#&gt; 6 rstudio::conf 2022 NA</span></span></code></pre></div>
<p>As well as the functions in pillar, the <a href="https://cli.r-lib.org/">cli</a> package provides a variety of
tools for styling text.</p>
</div>
<div id="truncation" class="section level2">
<h2>Truncation</h2>
<p>Tibbles can automatically compacts columns when theres no enough
horizontal space to display everything:</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><span class="fu">print</span>(data, <span class="at">width =</span> <span class="dv">30</span>)</span>
<span id="cb9-2"><a href="#cb9-2" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb9-3"><a href="#cb9-3" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb9-4"><a href="#cb9-4" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;latlon&gt;</span></span>
<span id="cb9-5"><a href="#cb9-5" tabindex="-1"></a><span class="co">#&gt; 1 rstu… 2017 28°20&#39;N 81°33&#39;W</span></span>
<span id="cb9-6"><a href="#cb9-6" tabindex="-1"></a><span class="co">#&gt; 2 rstu… 2018 32°43&#39;N 117°10&#39;W</span></span>
<span id="cb9-7"><a href="#cb9-7" tabindex="-1"></a><span class="co">#&gt; 3 rstu… 2019 30°16&#39;N 97°44&#39;W</span></span>
<span id="cb9-8"><a href="#cb9-8" tabindex="-1"></a><span class="co">#&gt; 4 rstu… 2020 37°47&#39;N 122°25&#39;W</span></span>
<span id="cb9-9"><a href="#cb9-9" tabindex="-1"></a><span class="co">#&gt; 5 rstu… 2021 28°30&#39;N 81°24&#39;W</span></span>
<span id="cb9-10"><a href="#cb9-10" tabindex="-1"></a><span class="co">#&gt; 6 rstu… 2022 NA</span></span></code></pre></div>
<p>Currently the latlon class isnt ever compacted because we havent
specified a minimum width when constructing the shaft. Lets fix that
and re-print the data:</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 pillar pillar_shaft</span></span>
<span id="cb10-2"><a href="#cb10-2" tabindex="-1"></a><span class="co">#&#39; @export</span></span>
<span id="cb10-3"><a href="#cb10-3" tabindex="-1"></a>pillar_shaft.earth_latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(x, ...) {</span>
<span id="cb10-4"><a href="#cb10-4" tabindex="-1"></a> out <span class="ot">&lt;-</span> <span class="fu">format</span>(x)</span>
<span id="cb10-5"><a href="#cb10-5" tabindex="-1"></a> pillar<span class="sc">::</span><span class="fu">new_pillar_shaft_simple</span>(out, <span class="at">align =</span> <span class="st">&quot;right&quot;</span>, <span class="at">min_width =</span> <span class="dv">10</span>)</span>
<span id="cb10-6"><a href="#cb10-6" tabindex="-1"></a>}</span>
<span id="cb10-7"><a href="#cb10-7" tabindex="-1"></a></span>
<span id="cb10-8"><a href="#cb10-8" tabindex="-1"></a><span class="fu">print</span>(data, <span class="at">width =</span> <span class="dv">30</span>)</span>
<span id="cb10-9"><a href="#cb10-9" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb10-10"><a href="#cb10-10" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb10-11"><a href="#cb10-11" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;latlon&gt;</span></span>
<span id="cb10-12"><a href="#cb10-12" tabindex="-1"></a><span class="co">#&gt; 1 rstudio::c… 2017 28°20&#39;N …</span></span>
<span id="cb10-13"><a href="#cb10-13" tabindex="-1"></a><span class="co">#&gt; 2 rstudio::c… 2018 32°43&#39;N 1…</span></span>
<span id="cb10-14"><a href="#cb10-14" tabindex="-1"></a><span class="co">#&gt; 3 rstudio::c… 2019 30°16&#39;N …</span></span>
<span id="cb10-15"><a href="#cb10-15" tabindex="-1"></a><span class="co">#&gt; 4 rstudio::c… 2020 37°47&#39;N 1…</span></span>
<span id="cb10-16"><a href="#cb10-16" tabindex="-1"></a><span class="co">#&gt; 5 rstudio::c… 2021 28°30&#39;N …</span></span>
<span id="cb10-17"><a href="#cb10-17" tabindex="-1"></a><span class="co">#&gt; 6 rstudio::c… 2022 NA</span></span></code></pre></div>
</div>
<div id="adaptive-rendering" class="section level2">
<h2>Adaptive rendering</h2>
<p>Truncation may be useful for character data, but for lat-lon data
itd be nicer to show full degrees and remove the minutes. Well first
write a function that does this:</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>deg <span class="ot">&lt;-</span> <span class="cf">function</span>(x, direction) {</span>
<span id="cb11-2"><a href="#cb11-2" tabindex="-1"></a> pm <span class="ot">&lt;-</span> <span class="cf">if</span> (direction <span class="sc">==</span> <span class="st">&quot;lat&quot;</span>) <span class="fu">c</span>(<span class="st">&quot;N&quot;</span>, <span class="st">&quot;S&quot;</span>) <span class="cf">else</span> <span class="fu">c</span>(<span class="st">&quot;E&quot;</span>, <span class="st">&quot;W&quot;</span>)</span>
<span id="cb11-3"><a href="#cb11-3" tabindex="-1"></a></span>
<span id="cb11-4"><a href="#cb11-4" tabindex="-1"></a> sign <span class="ot">&lt;-</span> <span class="fu">sign</span>(x)</span>
<span id="cb11-5"><a href="#cb11-5" tabindex="-1"></a> x <span class="ot">&lt;-</span> <span class="fu">abs</span>(x)</span>
<span id="cb11-6"><a href="#cb11-6" tabindex="-1"></a> deg <span class="ot">&lt;-</span> <span class="fu">round</span>(x)</span>
<span id="cb11-7"><a href="#cb11-7" tabindex="-1"></a></span>
<span id="cb11-8"><a href="#cb11-8" tabindex="-1"></a> ret <span class="ot">&lt;-</span> <span class="fu">sprintf</span>(<span class="st">&quot;%d°%s&quot;</span>, deg, pm[<span class="fu">ifelse</span>(sign <span class="sc">&gt;=</span> <span class="dv">0</span>, <span class="dv">1</span>, <span class="dv">2</span>)])</span>
<span id="cb11-9"><a href="#cb11-9" tabindex="-1"></a> <span class="fu">format</span>(ret, <span class="at">justify =</span> <span class="st">&quot;right&quot;</span>)</span>
<span id="cb11-10"><a href="#cb11-10" tabindex="-1"></a>}</span></code></pre></div>
<p>Then use it as part of more sophisticated implementation of the
<code>pillar_shaft()</code> method:</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 pillar pillar_shaft</span></span>
<span id="cb12-2"><a href="#cb12-2" tabindex="-1"></a><span class="co">#&#39; @export</span></span>
<span id="cb12-3"><a href="#cb12-3" tabindex="-1"></a>pillar_shaft.earth_latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(x, ...) {</span>
<span id="cb12-4"><a href="#cb12-4" tabindex="-1"></a> deg <span class="ot">&lt;-</span> <span class="fu">format</span>(x, <span class="at">formatter =</span> deg)</span>
<span id="cb12-5"><a href="#cb12-5" tabindex="-1"></a> deg_min <span class="ot">&lt;-</span> <span class="fu">format</span>(x)</span>
<span id="cb12-6"><a href="#cb12-6" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" tabindex="-1"></a> pillar<span class="sc">::</span><span class="fu">new_pillar_shaft</span>(</span>
<span id="cb12-8"><a href="#cb12-8" tabindex="-1"></a> <span class="fu">list</span>(<span class="at">deg =</span> deg, <span class="at">deg_min =</span> deg_min),</span>
<span id="cb12-9"><a href="#cb12-9" tabindex="-1"></a> <span class="at">width =</span> pillar<span class="sc">::</span><span class="fu">get_max_extent</span>(deg_min),</span>
<span id="cb12-10"><a href="#cb12-10" tabindex="-1"></a> <span class="at">min_width =</span> pillar<span class="sc">::</span><span class="fu">get_max_extent</span>(deg),</span>
<span id="cb12-11"><a href="#cb12-11" tabindex="-1"></a> <span class="at">class =</span> <span class="st">&quot;pillar_shaft_latlon&quot;</span></span>
<span id="cb12-12"><a href="#cb12-12" tabindex="-1"></a> )</span>
<span id="cb12-13"><a href="#cb12-13" tabindex="-1"></a>}</span></code></pre></div>
<p>Now the <code>pillar_shaft()</code> method returns an object of class
<code>&quot;pillar_shaft_latlon&quot;</code> created by
<code>new_pillar_shaft()</code>. This object contains the necessary
information to render the values, and also minimum and maximum width
values. For simplicity, both formats are pre-rendered, and the minimum
and maximum widths are computed from there.
(<code>get_max_extent()</code> is a helper that computes the maximum
display width occupied by the values in a character vector.)</p>
<p>All thats left to do is to implement a <code>format()</code> method
for our new <code>&quot;pillar_shaft_latlon&quot;</code> class. This method will
be called with a <code>width</code> argument, which then determines
which of the formats to choose. The formatting of our choice is passed
to the <code>new_ornament()</code> function:</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><span class="co">#&#39; @export</span></span>
<span id="cb13-2"><a href="#cb13-2" tabindex="-1"></a>format.pillar_shaft_latlon <span class="ot">&lt;-</span> <span class="cf">function</span>(x, width, ...) {</span>
<span id="cb13-3"><a href="#cb13-3" tabindex="-1"></a> <span class="cf">if</span> (<span class="fu">get_max_extent</span>(x<span class="sc">$</span>deg_min) <span class="sc">&lt;=</span> width) {</span>
<span id="cb13-4"><a href="#cb13-4" tabindex="-1"></a> ornament <span class="ot">&lt;-</span> x<span class="sc">$</span>deg_min</span>
<span id="cb13-5"><a href="#cb13-5" tabindex="-1"></a> } <span class="cf">else</span> {</span>
<span id="cb13-6"><a href="#cb13-6" tabindex="-1"></a> ornament <span class="ot">&lt;-</span> x<span class="sc">$</span>deg</span>
<span id="cb13-7"><a href="#cb13-7" tabindex="-1"></a> }</span>
<span id="cb13-8"><a href="#cb13-8" tabindex="-1"></a></span>
<span id="cb13-9"><a href="#cb13-9" tabindex="-1"></a> pillar<span class="sc">::</span><span class="fu">new_ornament</span>(ornament, <span class="at">align =</span> <span class="st">&quot;right&quot;</span>)</span>
<span id="cb13-10"><a href="#cb13-10" tabindex="-1"></a>}</span>
<span id="cb13-11"><a href="#cb13-11" tabindex="-1"></a></span>
<span id="cb13-12"><a href="#cb13-12" tabindex="-1"></a>data</span>
<span id="cb13-13"><a href="#cb13-13" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb13-14"><a href="#cb13-14" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb13-15"><a href="#cb13-15" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;latlon&gt;</span></span>
<span id="cb13-16"><a href="#cb13-16" tabindex="-1"></a><span class="co">#&gt; 1 rstudio::conf 2017 28°20&#39;N 81°33&#39;W</span></span>
<span id="cb13-17"><a href="#cb13-17" tabindex="-1"></a><span class="co">#&gt; 2 rstudio::conf 2018 32°43&#39;N 117°10&#39;W</span></span>
<span id="cb13-18"><a href="#cb13-18" tabindex="-1"></a><span class="co">#&gt; 3 rstudio::conf 2019 30°16&#39;N 97°44&#39;W</span></span>
<span id="cb13-19"><a href="#cb13-19" tabindex="-1"></a><span class="co">#&gt; 4 rstudio::conf 2020 37°47&#39;N 122°25&#39;W</span></span>
<span id="cb13-20"><a href="#cb13-20" tabindex="-1"></a><span class="co">#&gt; 5 rstudio::conf 2021 28°30&#39;N 81°24&#39;W</span></span>
<span id="cb13-21"><a href="#cb13-21" tabindex="-1"></a><span class="co">#&gt; 6 rstudio::conf 2022 NA</span></span>
<span id="cb13-22"><a href="#cb13-22" tabindex="-1"></a><span class="fu">print</span>(data, <span class="at">width =</span> <span class="dv">30</span>)</span>
<span id="cb13-23"><a href="#cb13-23" tabindex="-1"></a><span class="co">#&gt; # A tibble: 6 × 3</span></span>
<span id="cb13-24"><a href="#cb13-24" tabindex="-1"></a><span class="co">#&gt; venue year loc</span></span>
<span id="cb13-25"><a href="#cb13-25" tabindex="-1"></a><span class="co">#&gt; &lt;chr&gt; &lt;int&gt; &lt;latlon&gt;</span></span>
<span id="cb13-26"><a href="#cb13-26" tabindex="-1"></a><span class="co">#&gt; 1 rstudio::c… 2017 28°N 82°W</span></span>
<span id="cb13-27"><a href="#cb13-27" tabindex="-1"></a><span class="co">#&gt; 2 rstudio::c… 2018 33°N 117°W</span></span>
<span id="cb13-28"><a href="#cb13-28" tabindex="-1"></a><span class="co">#&gt; 3 rstudio::c… 2019 30°N 98°W</span></span>
<span id="cb13-29"><a href="#cb13-29" tabindex="-1"></a><span class="co">#&gt; 4 rstudio::c… 2020 38°N 122°W</span></span>
<span id="cb13-30"><a href="#cb13-30" tabindex="-1"></a><span class="co">#&gt; 5 rstudio::c… 2021 28°N 81°W</span></span>
<span id="cb13-31"><a href="#cb13-31" tabindex="-1"></a><span class="co">#&gt; 6 rstudio::c… 2022 NA</span></span></code></pre></div>
</div>
<div id="testing" class="section level2">
<h2>Testing</h2>
<p>If you want to test the output of your code, you can compare it with
a known state recorded in a text file. The
<code>testthat::expect_snapshot()</code> function offers an easy way to
test output-generating functions. It takes care about details such as
Unicode, ANSI escapes, and output width. Furthermore it wont make the
tests fail on CRAN. This is important because your output may rely on
details out of your control, which should be fixed eventually but should
not lead to your package being removed from CRAN.</p>
<p>Use this testthat expectation in one of your test files to create a
snapshot test:</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">expect_snapshot</span>(<span class="fu">pillar_shaft</span>(data<span class="sc">$</span>loc))</span></code></pre></div>
<p>See <a href="https://testthat.r-lib.org/articles/snapshotting.html" class="uri">https://testthat.r-lib.org/articles/snapshotting.html</a>
for more information.</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>