Skip to content

Commit

Permalink
clean up post
Browse files Browse the repository at this point in the history
  • Loading branch information
prncevince committed Oct 30, 2023
1 parent 7fd3956 commit f0020bf
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 24 deletions.
18 changes: 9 additions & 9 deletions _site/posts/geo/maps-ggplot-svglite/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@
<img src="usapop-ggplot-svglite-3x-3fps-1920w-80lossy-O3.gif" class="img-fluid figure-img">
</div>
<figcaption class="figure quarto-float-caption quarto-float-fig" id="fig-usapop-gif-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figure&nbsp;1: A choropleth map of the population within each county of the continental United States in 2015. <br><br> The map was designed using <a href="https://ggplot2-book.org">ggplot2</a>. Saving the map using <a href="https://svglite.r-lib.org">svglite</a> and editing the output has the potential to create beautiful interactive &amp; lightweight maps.
Figure&nbsp;1: A choropleth map visualizing the population within each county of the continental United States in 2015. <br><br> The map was designed using <a href="https://ggplot2-book.org">ggplot2</a>. Saving the map using <a href="https://svglite.r-lib.org">svglite</a> and editing the output has the potential to create beautiful interactive &amp; lightweight maps.
</figcaption></figure>
</div>
<section id="tldr" class="level2"><h2 class="anchored" data-anchor-id="tldr">TLDR</h2>
Expand All @@ -273,10 +273,10 @@
<p>At the end of November, I plan on packing up my belongings and trekking 6,500 miles across the continental United States from Virginia out to the West coast (🗣️ roadtrip 🛣️).</p>
<p>Being who I am, I figured it’d be a great idea to plot out the journey using R. Additionally, the <a href="https://30daymapchallenge.com/">#30DayMapChallenge</a> is approaching, so I figured that it was a great time to create a new thing in preparation for the challenge. Most of my time went into development over the past week, so the next steps for me are the trip planning, but I think the proof of concept is a great start!</p>
</section><section id="thoughts-on-data-driven-javascript-visuals" class="level2"><h2 class="anchored" data-anchor-id="thoughts-on-data-driven-javascript-visuals">Thoughts on Data Driven JavaScript Visuals</h2>
<p>Plots &amp; maps are cool, and interactive plots can be even cooler, but the bloat of adding external JavaScript libraries can sometimes create a performance hit to a users’ experience on the web. A typically approach within the <a href="../../../posts/#category=R" target="_blank">R</a> user community to embed data driven interactive graphics in web content involves using the incredible <a href="http://htmlwidgets.org">htmlwidgets</a> package. There are <a href="http://www.htmlwidgets.org/showcase_leaflet.html">several</a> HTML widget R packages. These packages work by using {htmlwidgets} to bind &amp; format data as JSON input to their respective JavaScript visualization libraries and then to output the results as an HTML element.</p>
<p>My biggest gripe with HTML widgets is that they embed the entire JavaScript library passed to them. So, if you say want <strong>2</strong> unique HTML widgets on your web page that are created from the same {htmlwidgets} binding R package, then you’ll have <strong>2</strong> identical copies of the same JavaScript library downloaded to your web browser. Having the option to embed the library in say your web pages <code>&lt;head&gt;</code> element could help cut down on some of this bloat.</p>
<p>Plots &amp; maps are cool, and interactive plots can be even cooler, but the bloat of adding external JavaScript libraries can sometimes create a performance hit to a users’ experience on the web. A typically approach within the <a href="../../../posts/#category=R" target="_blank">R</a> user community to embed data driven interactive graphics in web content involves using the incredible <a href="http://htmlwidgets.org">htmlwidgets</a> package. There are <a href="http://www.htmlwidgets.org/showcase_leaflet.html">several</a> HTML widget R packages. These packages work by using htmlwidgets to bind &amp; format data as JSON input to their respective JavaScript visualization libraries and then to output the results as an HTML element.</p>
<p>My biggest gripe with HTML widgets is that they embed the entire JavaScript library passed to them. So, if you say want <strong>2</strong> unique HTML widgets on your web page that are created from the same htmlwidgetsbinding R package, then you’ll have <strong>2</strong> identical copies of the same JavaScript library downloaded to your web browser. Having the option to embed the library in say your web pages <code>&lt;head&gt;</code> element could help cut down on some of this bloat.</p>
<p>Aside from this, I think that being able to create data driven interactive graphics without the need for external JavaScript libraries has a lot of potential when it comes to creating beautiful plots in the browser. Building plots with SVG has been conquered by <a href="https://d3js.org">D3.js</a> as well as many others that have taken significant influence from D3, such as <a href="https://plotly.com">plotly</a> &amp; <a href="https://jkunst.com/highcharter/">highcharter</a>. Additionally, <a href="https://observablehq.com/about">Observable</a> has changed the game when it comes to quickly prototyping &amp; sharing new data visuals in the browser. Making it easier than ever before to collaborate &amp; maximize one’s reach when developing a new dataviz powered by web technologies. In particular, its lead by Mike Bostock, one who I would call a super human with <a href="https://bost.ocks.org/mike/algorithms/">eons</a> of data visualization expertise. At Observable, they’re building the <a href="https://observablehq.com/plot">Observable Plot</a> library to help folks efficiently visualize tabluar data in the browser.</p>
<p>Plot is inspired by <a href="http://vita.had.co.nz/papers/layered-grammar.pdf"><strong>the grammar of graphics</strong></a> style, which is the foundation that {ggplot2} was built upon. I think that the ability to turn a ggplot into a an interactive graphic can be extremely powerful and can open up many new doors into the world of dataviz. Using plotly and the incredible <a href="https://blog.cpsievert.me/2018/01/30/learning-improving-ggplotly-geom-sf"><code>plotly::ggplotly</code></a> designed by Carson Sievert is an htmlwidgets approach to doing this. The approach to use {svglite} to save ggplot2 created plots and then post process these graphics allows you to keep the design portion of the dataviz mostly outside of the web browser and within the Plot pane of your IDE (i.e.&nbsp;RStudio). The choice to post process the SVG output within R allows one to minimize JavaScript library dependencies, but presents the challenge of making the SVG interactive.</p>
<p>Plot is inspired by <a href="http://vita.had.co.nz/papers/layered-grammar.pdf"><strong>the grammar of graphics</strong></a> style, which is the foundation that <a href="https://ggplot2.tidyverse.org">ggplot2</a> was built upon. I think that the ability to turn a ggplot into a an interactive graphic can be extremely powerful and can open up many new doors into the world of dataviz. Using plotly and the incredible <a href="https://blog.cpsievert.me/2018/01/30/learning-improving-ggplotly-geom-sf"><code>plotly::ggplotly</code></a> designed by Carson Sievert is an htmlwidgets approach to doing this. The approach to use <a href="https://svglite.r-lib.org">svglite</a> to save ggplot2 created plots and then post process these graphics allows you to keep the design portion of the dataviz mostly outside of the web browser and within the Plot pane of your IDE (i.e.&nbsp;RStudio). The choice to post process the SVG output within R allows one to minimize JavaScript library dependencies, but presents the challenge of making the SVG interactive.</p>
<p>All in all, I’m excited to see where this goes.</p>
</section><section id="the-data" class="level2"><h2 class="anchored" data-anchor-id="the-data">The data</h2>
<p>I used the 2015 U.S. Census county population data stored within the <a href="https://usmap.dev">usmap</a> package. More updated U.S. Census data from the U.S Census Bureau can be accessed via the <a href="https://walker-data.com/tidycensus/">tidycencus</a> and <a href="https://www.hrecht.com/censusapi/">censusapi</a> R packages.</p>
Expand Down Expand Up @@ -338,10 +338,10 @@
</div>
</section><section id="the-ggplot" class="level2 page-columns page-full"><h2 class="anchored" data-anchor-id="the-ggplot">The ggplot</h2>
<p>With the <a href="https://github.com/yixuan/showtext">showtext</a> package, I used a custom font that I downloaded from Fontsgeek, <a href="https://fontsgeek.com/fonts/Black-Chancery-Regular">Black Chancery</a>. Additionally, to give the plot a bit of a 3D effect, I added shadow using <a href="https://ggfx.data-imaginist.com">ggfx</a>. It adds some <a href="https://www.data-imaginist.com/2021/say-goodbye-to-good-taste/">good taste</a> IMO.</p>
<p>When it came to trying to save an identical copy of the rendered ggplot graphic within the RStudio Plot pane programmatically, I’ve found this to be very challenging. The <code>ggplot::ggsave</code> function has <code>width</code>, <code>height</code>, <code>unit</code>, &amp; <code>dpi</code> parameters that can be specified. There’s also a great <a href="https://www.christophenicault.com/post/understand_size_dimension_ggplot2/">post by Christophe Nicault</a> on setting the text DPI via the <a href="https://github.com/yixuan/showtext">showtext</a> package to match the DPI used within <code>ggsave</code> by the PNG graphics device. However on my 14” MBP, these methods all seem to fall short, the with ggsave approach font being larger than font displayed in the Plot pane. It seems that the Plot pane does some magic when it comes to resizing. You can right click your image &amp; choose “Save image as…”, which allows you to save <strong><em>what you’re looking at</em></strong> to file.</p>
<p>I think that there are benefits &amp; drawbacks to both approaches. Below I provide the ggplot code version of the map. The last line of the snippet includes a <code>ggsave</code> call that builds a plot with text slightly bigger than what’s expected. Additionally, the <a href="https://ggfx.data-imaginist.com">ggfx</a> shadow seems less prominent in the <code>ggsave</code> version, and the overall width / height of the plot content appear smaller as well.</p>
<p>When it came to trying to save an identical copy of the rendered ggplot graphic within the RStudio Plot pane programmatically, I’ve found this to be very challenging. The <code>ggplot::ggsave</code> function has <code>width</code>, <code>height</code>, <code>unit</code>, &amp; <code>dpi</code> parameters that can be specified. There’s also a great <a href="https://www.christophenicault.com/post/understand_size_dimension_ggplot2/">post by Christophe Nicault</a> on setting the text DPI via the <a href="https://github.com/yixuan/showtext">showtext</a> package to match the DPI used within <code>ggsave</code> by the PNG graphics device. However on my 14” MBP, these methods all seem to fall short, with the ggsave approach font being larger than the font displayed in the Plot pane. It seems that the Plot pane does some magic when it comes to resizing. You can right click your image &amp; choose “Save image as…”, which allows you to save <strong><em>what you’re looking at</em></strong> to file.</p>
<p>I think that there are benefits &amp; drawbacks to both approaches. Below I provide the ggplot code version of the map. The last line of the snippet includes a <code>ggsave</code> call that builds a plot with text slightly bigger than what’s expected. Additionally, the ggfx shadow seems less prominent in the <code>ggsave</code> version, and the overall width / height of the plot content appear smaller as well.</p>
<p>Thus, I’ve included both versions in <a href="#fig-usapop-ggplot" class="quarto-xref">Figure&nbsp;2</a> for comparison, the version that I saved from the RStudio plot pane, as well as the <code>ggsave</code> version. MacOS Preview app info on the <code>.png</code> tells me that the plot pane version ends up saving with <code>72</code> dpi (dots per inch), while the <code>ggsave</code> version has <code>254</code> as I’ve specified. Both files have near equivalent pixel size dimensions (<code>3023 × 1889</code>), with the key difference being the dpi.</p>
<p>Even if we switch the <code>dpi</code> to <code>72</code>, and calculate the same width / height of the RStudio pane version to get the same resolution image in the <code>ggsave</code> version, i.e.&nbsp;both dpi &amp; pixel width/height match amongst both files, we get even smaller text and other distortions.</p>
<div class="page-columns page-full"><p></p><div class="no-row-height column-margin column-container"><span class="">Even if we switch the <code>dpi</code> to <code>72</code>, and calculate the same width / height of the RStudio pane version to get the same resolution image in the <code>ggsave</code> version, i.e.&nbsp;both dpi &amp; pixel width/height match amongst both files, we get even smaller text and other distortions.</span></div></div>
<div class="cell">
<details><summary>usapop-ggplot.R</summary><div class="sourceCode cell-code" id="cb2"><pre class="sourceCode numberSource r number-lines code-with-copy"><code class="sourceCode r"><span id="cb2-1"><a href="#cb2-1"></a><span class="fu">library</span>(sf)</span>
<span id="cb2-2"><a href="#cb2-2"></a><span class="fu">library</span>(ggfx)</span>
Expand Down Expand Up @@ -418,7 +418,7 @@
</div>
</div>
</section><section id="svg-xml-editting" class="level2"><h2 class="anchored" data-anchor-id="svg-xml-editting">SVG &amp; XML Editting</h2>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a> (Scalar Vector Graphics) is itself its own markup language, based in <a href="https://developer.mozilla.org/en-US/docs/Web/XML">XML</a> and similar to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML">HTML</a>. The key difference between HTML &amp; SVG being that HTML specifies how text is displayed to the browser versus SVG describes how graphics are displayed.</p>
<p><a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a> (Scalar Vector Graphics) is itself its own markup language, based in <a href="https://developer.mozilla.org/en-US/docs/Web/XML">XML</a> and similar to <a href="https://developer.mozilla.org/en-US/docs/Web/HTML">HTML</a>. The key difference between HTML &amp; SVG being that HTML specifies how text is displayed to the browser, while SVG describes how graphics are displayed.</p>
<p>Because SVG files are written as XML, they can be loaded as objects and edited in scripting languages, similar to how commonly used web scraping tools work. Using the <a href="https://xml2.r-lib.org/">xml2</a> &amp; <a href="https://rvest.tidyverse.org/">rvest</a> packages in combination from the <a href="https://tidyverse.tidyverse.org">tidyverse</a> can help us run query selectors on the XML markup to add and remove XML element nodes as necessary.</p>
<p>Using the <a href="https://svglite.r-lib.org">svglite</a> package/graphics device within <code>ggsave</code> function calls, we can convert &amp; save ggplots to SVG elements, and even use our custom fonts within them.</p>
<div class="callout callout-style-default callout-note callout-titled">
Expand All @@ -435,7 +435,7 @@
</div>
</div>
<section id="adding-iteractivity" class="level3"><h3 class="anchored" data-anchor-id="adding-iteractivity">Adding Iteractivity</h3>
<p>Using vanilla JavaScript, I add a tooltip that reads the <code>title</code> attribute of each county boundary SVG <code>&lt;path&gt;</code> within the created choropleth group (<code>&lt;g&gt;</code>) element, e.g <code>&lt;g class="tooltip"&gt;&lt;rect/&gt;&lt;text&gt;&lt;/text&gt;&lt;/g&gt;</code>. The tooltip SVG element itself is a single <code>&lt;rect&gt;</code> &amp; <code>&lt;text&gt;</code> pair rapped in a group. When creating the SVG/XML document in R, I add it as the <em>last</em> graphic element in the <code>&lt;svg&gt;</code> container so that it displays on top of everything else. JavaScript handles updating the content of the <code>&lt;text&gt;</code> using event handlers on mouse movement. The tooltip was inspired by Lee Mason’s <a href="https://observablehq.com/@siliconjazz/basic-svg-tooltip">Basic SVG Tooltip</a> Observable notebook. It differs in that it’s implemented as native SVG, rather than using a <code>&lt;div&gt;</code> wrapped in a <code>&lt;foreignObject&gt;</code>, which is incompatible in all browsers.</p>
<p>Using vanilla JavaScript, I add a tooltip that reads the <code>title</code> attribute of each county boundary SVG <code>&lt;path&gt;</code> within the created choropleth group (<code>&lt;g&gt;</code>) element, e.g <code>&lt;g class="tooltip"&gt;&lt;rect/&gt;&lt;text&gt;&lt;/text&gt;&lt;/g&gt;</code>. The SVG tooltip element itself is a single <code>&lt;rect/&gt;</code> &amp; <code>&lt;text&gt;</code> pair rapped in a group. When creating the SVG/XML document in R, I add it as the <em>last</em> graphic element in the <code>&lt;svg&gt;</code> container so that it displays on top of everything else. JavaScript handles updating the content of the <code>&lt;text&gt;</code> using event handlers on mouse movement. The tooltip was inspired by Lee Mason’s <a href="https://observablehq.com/@siliconjazz/basic-svg-tooltip">Basic SVG Tooltip</a> Observable notebook. It differs in that it’s implemented as native SVG, rather than using a <code>&lt;div&gt;</code> wrapped in a <code>&lt;foreignObject&gt;</code>, which is incompatible in all browsers.</p>
<div data-add-from="../../../about/usapop.js" data-code-filename="usapop.js">
<details><summary>Code</summary><div class="sourceCode cell-code" id="cb3"><pre class="sourceCode numberSource javascript number-lines code-with-copy"><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1"></a>svgChoro <span class="op">=</span> <span class="bu">document</span><span class="op">.</span><span class="fu">querySelector</span>(<span class="st">'svg.svglite &gt; g.choro'</span>)</span>
<span id="cb3-2"><a href="#cb3-2"></a>svgBords <span class="op">=</span> <span class="bu">document</span><span class="op">.</span><span class="fu">querySelector</span>(<span class="st">'svg.svglite &gt; g.borders'</span>)</span>
Expand Down
2 changes: 1 addition & 1 deletion _site/posts/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ <h1 class="title">Big &amp; <span style="font-size:0.75rem;vertical-align:middle
</div>
</div>
<div class="list grid quarto-listing-cols-3">
<div class="g-col-1" data-index="0" data-categories="ggplot2,R,Geospatial,svglite,SVG,JavaScript,rspatial,tidyverse,30DayMapChallenge" data-listing-date-sort="1698552000000" data-listing-file-modified-sort="1698645918333" data-listing-date-modified-sort="1698645918000" data-listing-reading-time-sort="9" data-listing-word-count-sort="1746">
<div class="g-col-1" data-index="0" data-categories="ggplot2,R,Geospatial,svglite,SVG,JavaScript,rspatial,tidyverse,30DayMapChallenge" data-listing-date-sort="1698552000000" data-listing-file-modified-sort="1698648826423" data-listing-date-modified-sort="1698648826000" data-listing-reading-time-sort="9" data-listing-word-count-sort="1746">
<a href="../posts/geo/maps-ggplot-svglite/index.html" class="quarto-grid-link">
<div class="quarto-grid-item card h-100 card-left">
<p class="card-img-top"><img src="geo/maps-ggplot-svglite/usapop-ggplot-svglite-3x-3fps-1920w-80lossy-O3.gif" style="height: 150px;" class="thumbnail-image card-img"/></p>
Expand Down
Loading

0 comments on commit f0020bf

Please sign in to comment.