<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/visualizing-geo-spatial-data-with-sf-and-plotly/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/"> R – Modern Data</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>
<b><br>
Need help with R, data viz, and/or stats? <a rel="nofollow" href="https://consulting.cpsievert.me/" target="_blank">Work with me</a> or <a rel="nofollow" href="https://plotcon.plot.ly/workshops/r-shiny-dash-r" target="_blank">attend my 2 day workshop</a>!<br>
</b>
</p>
<p>In my <a rel="nofollow" href="https://blog.cpsievert.me/2018/01/30/learning-improving-ggplotly-geom-sf/" target="_blank">last post</a>, we explored interactive visualizations of <a rel="nofollow" href="https://r-spatial.github.io/sf/" target="_blank">simple features</a> (i.e., interactive maps) via <strong>ggplot2</strong>’s <code>geom_sf()</code> and <strong>plotly</strong>’s <code>ggplotly()</code>. This time we’ll make similar visualizations using <strong>plotly</strong>’s “non-ggplot2” mapping interfaces (namely <code>plot_ly()</code>, <code>plot_geo()</code>, and <code>plot_mapbox()</code>). Here’s a quick example of reading a shape file into R as simple features via <a rel="nofollow" href="https://r-spatial.github.io/sf/reference/st_read.html" target="_blank"><code>st_read()</code></a>, then plotting those features (in this case, North Carolina counties) using each one of the four mapping approaches <strong>plotly</strong> provides. Notice how all of these options auto-magically know how to render simple features:</p>

<pre># to replicate these examples, you currently need the dev version
# devtools::install_github('ropensci/plotly')
library(plotly)

nc &lt;- sf::st_read(system.file(&quot;shape/nc.shp&quot;, package = &quot;sf&quot;), quiet = TRUE)
class(nc)</pre>

<pre>#> [1] &quot;sf&quot;         &quot;data.frame&quot;</pre>

<pre>subplot(nrows = 2,
  ggplot(nc) + geom_sf(),
  plot_ly(nc),
  plot_geo(nc),
  plot_mapbox(nc)
) %>% hide_legend()</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/06-sf-options.html" target="_blank"><br>
<img src="https://i0.wp.com/i.imgur.com/nZujcuv.png?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>You might be wondering, “What can <strong>plotly</strong> offer over other interactive mapping packages such as <a rel="nofollow" href="https://cran.r-project.org/package=leaflet" target="_blank"><strong>leaflet</strong></a>, <a rel="nofollow" href="https://cran.r-project.org/package=mapview" target="_blank"><strong>mapview</strong></a>, <a rel="nofollow" href="https://cran.r-project.org/package=mapedit" target="_blank"><strong>mapedit</strong></a>, etc?”. One big feature is the <a rel="nofollow" href="https://plotly-book.cpsievert.me/linking-views-without-shiny.html" target="_blank">linked brushing framework</a>, which works best when linking <strong>plotly</strong> together with other <strong>plotly</strong> graphs (i.e., only a subset of brushing features are supported when linking to other <a rel="nofollow" href="https://rstudio.github.io/crosstalk/widgets.html" target="_blank">crosstalk-compatible htmlwidgets</a>). Another is the ability to leverage the <a rel="nofollow" href="https://plot.ly/javascript/plotlyjs-function-reference/" target="_blank">plotly.js API</a> to make efficient updates in shiny apps <a rel="nofollow" href="https://blog.cpsievert.me/2017/07/13/plotly-4.7.1-now-on-cran/" target="_blank">via <code>plotlyProxy()</code></a>. Speaking of efficiency, <a rel="nofollow" href="https://plot.ly/javascript/" target="_blank">plotly.js</a> keeps on improving the performance of their WebGL-based rendering, so I recommend trying <code>plot_ly()</code> (with <code>toWebGL()</code>) and/or <code>plot_mapbox()</code> if you have lots of graphical elements to render. Also, by having a consistent interface between these various mapping approaches, it’s much quicker and easier to switch from one approach to another when you need to leverage a different set of <a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#strengths-weaknesses" target="_blank">strengths and weaknesses</a>.</p>
<p>Speaking of strengths, plotly.js also has <img alt="🌎" src="https://i0.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f30e.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1">-class 3D rendering support. When used in combination with <strong>plotly</strong>’s linking framework, we can do some nifty things – all inside self-contained HTML! For example, <a rel="nofollow" href="https://blog.cpsievert.me/sf-plotly-3D-globe.html" target="_blank">here are linked 3D &amp; 2D views</a> of tropical storm paths which is useful for querying anomalies and provides some insight into the relationship between distance traveled, altitude, latitude, and longitude:<a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fn1" target="_blank"><sup>1</sup></a></p>
<p></p>
<pre># To see the actual R code that generates the self-contained HTML result,
# enter this in your R console or visit https://github.com/ropensci/plotly/tree/master/demo
demo(&quot;sf-plotly-3D-globe&quot;, package = &quot;plotly&quot;)</pre>
<p><iframe allowfullscreen src="https://player.vimeo.com/video/257149623" width="450"><br>
</iframe></p>
<p>As you’ll see in the <a rel="nofollow" href="https://github.com/ropensci/plotly/blob/master/NEWS.md" target="_blank">NEWS</a> of the development version, I’ve also added new <code>stroke</code> and <code>span</code> arguments which make it easier to control the outline color and width of filled polygons/markers/bars/etc. These new arguments work in a similar way to existing arguments like <code>color</code> and <code>linetype</code>. In particular, constant values can be specified via <code>I()</code>:</p>

<pre>plot_ly(nc, stroke = I(&quot;#119dff&quot;), span = I(5), color = I(&quot;#00cc96&quot;), linetype = I(&quot;dash&quot;))</pre>

<p><img src="https://i1.wp.com/i.imgur.com/AEv3EiO.png?w=100%25&ssl=1" data-recalc-dims="1"></p>
<p>Furthermore, values not wrapped in <code>I()</code> are mapped to a visual range defined by the plural form of the argument (i.e., <code>strokes</code> and <code>spans</code>). However, to effectively map data to these sorts of visuals, we might want to generate mutliple traces.</p>
<div>
<h2>One trace to rule them all?</h2>
<p>One of the trickiest things about <a rel="nofollow" href="http://consulting.cpsievert.me/#Training" target="_blank">mastering <strong>plotly</strong></a> and/or plotly.js is knowing what can and can not be done with just one trace. As I <a rel="nofollow" href="https://plotly-book.cpsievert.me/scatter-traces.html#line-plots" target="_blank">elude to in the <em>plotly for R</em> book</a>, if something can be implemented with a single trace, then it should, because traces don’t scale very well (i.e., can easily lead to a sluggish plot). That’s why, by default, the maps above are implemented with just one trace.<a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fn2" target="_blank"><sup>2</sup></a> However, when you need certain scalar (i.e., non-data-array) trace properties (e.g. <code>fillcolor</code>) to vary, you might want to use <code>split</code> to create a trace for every level in the <code>split</code> variable. For example, in this map of <a rel="nofollow" href="https://en.wikipedia.org/wiki/First-level_NUTS_of_the_European_Union" target="_blank">territories</a> in <a rel="nofollow" href="https://en.wikipedia.org/wiki/Franconia" target="_blank">Franconia</a>, we ensure one trace per territory (via the <code>split</code> argument), which leads to two fairly obvious features:</p>
<ol>
<li>The ability to hide/show territories by clicking (or double-clicking) legend entries. As we’ll discuss later, there are actually ways to do this sort of thing with <em>just one trace</em> via the <a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#crosstalk" target="_blank">crosstalk (i.e. linked views) framework</a>.</li>
<li>A different color for each territory. In this case, we’ve used <code>split</code> without specifying <code>color</code>, so plotly.js will impose it’s default coloring rules, but you could easily set a constant color across traces (e.g., <code>color = I(&quot;black&quot;)</code>) or, as we’ll see shortly, use a custom color scheme.</li>
</ol>
<pre># load trails data (an sf object bundled with the mapview package)
# install.packages('mapview')
data(franconia, package = &quot;mapview&quot;)

# Compare this result with: `plot_ly(franconia, split = ~NAME_ASCI, color = I(&quot;black&quot;))`
plot_ly(franconia, split = ~NAME_ASCI)</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/franconia-split.html" target="_blank"><br>
<img src="https://i0.wp.com/i.imgur.com/83FJOBA.gif?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>Having a different trace for each territory opens the door for further territory-level customization, such as having a custom color, linetype, fill-specific tooltip, etc. When <code>color</code> is <em>numeric</em>, and you want it to set a different fill-color for certain polygon(s), you’ll need <code>split</code> to ensure there is no more than one color per trace:</p>

<pre>plot_ly(
  franconia, 
  split = ~NUTS_ID,
  color = ~SHAPE_AREA,
  alpha = 1,
  showlegend = FALSE
)</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/franconia-choro.html" target="_blank"><br>
<img src="https://i0.wp.com/i.imgur.com/6oFCHiV.png?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>On the other hand, if <code>color</code> is a discrete variable, <code>plot_ly()</code> always produces one trace per level. Since, in this case, there are over 30 districts, I’m going to use <a rel="nofollow" href="https://stackoverflow.com/questions/21352683/randomising-qualitative-colours-for-large-sets-in-ggplot" target="_blank">a color palette</a> that does a fairly good job in distinguishing between a large number of groups:</p>

<pre>cols &lt;- c(&quot;#89C5DA&quot;, &quot;#DA5724&quot;, &quot;#74D944&quot;, &quot;#CE50CA&quot;, &quot;#3F4921&quot;, &quot;#C0717C&quot;, &quot;#CBD588&quot;, &quot;#5F7FC7&quot;, &quot;#673770&quot;, &quot;#D3D93E&quot;, &quot;#38333E&quot;, &quot;#508578&quot;, &quot;#D7C1B1&quot;, &quot;#689030&quot;, &quot;#AD6F3B&quot;, &quot;#CD9BCD&quot;, &quot;#D14285&quot;, &quot;#6DDE88&quot;, &quot;#652926&quot;, &quot;#7FDCC0&quot;, &quot;#C84248&quot;, &quot;#8569D5&quot;, &quot;#5E738F&quot;, &quot;#D1A33D&quot;, &quot;#8A7C64&quot;, &quot;#599861&quot;)
plot_ly(franconia, color = ~NAME_ASCI, colors = cols, alpha = 1)</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/franconia-color-discrete.html" target="_blank"><br>
<img src="https://i0.wp.com/i.imgur.com/LXrGpXx.png?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>Note that you can still <code>color</code> multiple traces the same color, but if you want to have a different tooltip to appear upon hovering a specific set of polygons (as opposed to along each point), you’ll want to still use <code>split</code> in combination with <code>hoveron = &quot;fill&quot;</code>:</p>

<pre>plot_ly(
  franconia,
  split = ~NUTS_ID,
  color = ~district,
  stroke = I(&quot;black&quot;),
  text = ~paste(NAME_ASCI, &quot;\n is in&quot;, district), 
  hoverinfo = &quot;text&quot;,
  hoveron = &quot;fill&quot;
)</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/franconia-color-split.html" target="_blank"><br>
<img src="https://i1.wp.com/i.imgur.com/XqkqQiS.png?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<div>
<h3>Leveraging mapbox basemaps</h3>
<p>Among the four mapping options, the one that excites me the most is <code>plot_mapbox()</code><a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fn3" target="_blank"><sup>3</sup></a>. The primary reason to use <code>plot_mapbox()</code> (or <code>plot_geo()</code>) over <code>geom_sf()</code> (or <code>plot_ly()</code>) is that these approaches include a base-map layer which updates dynamically on zoom and can quite helpful for providing geographic context. The base-map styling can be easily customized – especially for <code>plot_mapbox()</code> via the <a rel="nofollow" href="https://plot.ly/r/reference/#layout-mapbox-style" target="_blank"><code>layout.mapbox.style</code> attribute</a>. In addition to a URL to a <a rel="nofollow" href="https://www.mapbox.com/help/create-a-custom-style/" target="_blank">custom style</a>, you can provide this attribute with a pre-packaged style name. To get a list of those pre-packaged styles, reach into the plotly.js plot <a rel="nofollow" href="https://www.rdocumentation.org/packages/plotly/versions/4.7.1/topics/schema?tap_a=5644-dce66f&tap_s=10907-287229" target="_blank"><code>schema()</code></a>:</p>

<pre>styles &lt;- schema()$layout$layoutAttributes$mapbox$style$values
styles</pre>

<pre>[1] &quot;basic&quot;             &quot;streets&quot;           &quot;outdoors&quot;          &quot;light&quot;            
[5] &quot;dark&quot;              &quot;satellite&quot;         &quot;satellite-streets&quot;</pre>

<p>A nice feature to include with these maps is a dropdown to dynamically change the base-map styling. To do so, use the <a rel="nofollow" href="https://plot.ly/r/reference/#layout-updatemenus" target="_blank"><code>layout.updatemenus.buttons</code> attribute</a> to control the value of the <code>layout.mapbox.style</code> attribute. Since we wish to modify the <code>layout.mapbox.style</code> attribute, which is part of the plot’s layout, we’ll want each dropdown “button” to trigger a <a rel="nofollow" href="https://plot.ly/javascript/plotlyjs-function-reference/" target="_blank">relayout</a> event with the appropriate <code>args</code>. Here is one way to create a list of buttons, one for each of the default styles:</p>

<pre># generate plot.js buttons, one for every style 
style_buttons &lt;- lapply(styles, function(s) {
  list(label = s, method = &quot;relayout&quot;, args = list(&quot;mapbox.style&quot;, s))
})</pre>

<p>With our list of <code>style_buttons</code>, we’re now ready to visualize something. Here I’ll leverage the <code>trails</code> data from the <a rel="nofollow" href="https://r-spatial.github.io/mapview/" target="_blank"><strong>mapview</strong></a> package, which has a number of hiking trails of Franconia, Germany.</p>

<pre>data(trails, package = 'mapview')

plot_mapbox(trails, color = I(&quot;black&quot;)) %>%
  layout(
    title = &quot;Selected hiking trails in Franconia&quot;,
    mapbox = list(style = &quot;satellite-streets&quot;),
    updatemenus = list(list(y = 0.8, buttons = rev(style_buttons)))
  )</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/07-satellite.html" target="_blank"><br>
<img src="https://i2.wp.com/i.imgur.com/YgqpCup.png?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>As a side note, you could also <a rel="nofollow" href="https://blog.cpsievert.me/2017/07/13/plotly-4.7.1-now-on-cran/" target="_blank">use <strong>shiny</strong> to modify the basemap layer</a> without redrawing the entire plot, but the result here is self-contained HTML/SVG, which is <strong>much easier</strong> to share, host, scale, and maintain.</p>
</div>
<div>
<h3>Linking views without shiny</h3>
<p>In terms of linked brushing <em>in self-contained HTML</em>, <strong>plotly</strong> is definitely the most advanced <a rel="nofollow" href="https://rstudio.github.io/crosstalk/widgets.html" target="_blank"><strong>crosstalk</strong>-compatible htmlwidget</a>. You’ll be able to do more when linking <strong>plotly</strong> to <strong>plotly</strong>, but since <a rel="nofollow" href="https://github.com/rstudio/DT/pull/498" target="_blank">persistent selection was recently added to <strong>DT</strong></a>, let’s demonstrate linking <strong>plotly</strong> with <strong>DT</strong>. To link views via <strong>crosstalk</strong>, you’ll want to supply a data frame of interest to the <code>SharedData$new()</code> method and route the resulting object to any plots that you want to link. By default, the row index (which, in this case, is a simple feature) is used to define the graphical queries, but you can also reference a (discrete) variable to achieve <a rel="nofollow" href="http://vis.berkeley.edu/papers/generalized_selection/" target="_blank">generalized selections</a> (e.g., you could query all trails in a district via <code>SharedData$new(trails, ~district)</code>).<a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fn4" target="_blank"><sup>4</sup></a> Linking <strong>plotly</strong> with <strong>DT</strong> in this way gives us a pretty powerful way to identify simple features both <a rel="nofollow" href="https://plotly-book.cpsievert.me/linking-views-without-shiny.html#selection-via-indirect-manipulation" target="_blank">directly and indirectly</a>.</p>

<pre>library(crosstalk)
tsd &lt;- SharedData$new(trails)

bscols(
  plot_mapbox(tsd, text = ~FKN, hoverinfo = &quot;text&quot;),
  DT::datatable(tsd)
)</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/08-trails-dt.html" target="_blank"><br>
<img src="https://i0.wp.com/i.imgur.com/fsxwr5l.gif?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>To provide a sneak peak into the power of the linking framework in <strong>plotly</strong>, let’s leverage a fairly recent feature: brushing of aggregated traces. This example demonstrates how to brush a histogram, but a similar approach could be used to brush other aggregated traces (e.g., <code>add_histogram2d()</code>, <code>add_boxplot()</code>, etc). In fact, one could replicate this example with <code>add_bars()</code> (instead of <code>add_histogram()</code>) by pre-computing bars heights and <a rel="nofollow" href="https://plotly-book.cpsievert.me/linking-views-without-shiny.html#fig:density2scatter" target="_blank">using a list-column key</a> to assign multiple counties to each bar. In either case (<code>add_bars()</code> or <code>add_histogram()</code>), it is usually a good idea to set <code>layout.barmode = &quot;overlay&quot;</code> so that newly added bars don’t use the plotly.js default of dodging the existing bars. In the case where we let plotly.js dynamically compute aggregates (i.e., <code>add_histogram()</code>) it’s also a good idea to also define <code>xbins</code> (or <code>ybins</code>) so that binning of new bars use the same rules as the existing (i.e. initial) bars.</p>

<pre>ncsd &lt;- SharedData$new(nc)

bscols(
  plot_mapbox(ncsd) %>%
    highlight(dynamic = TRUE, persistent = TRUE),
  plot_ly(ncsd, x = ~AREA) %>% 
    add_histogram(xbins = list(start = 0, end = 0.3, size = 0.02)) %>%
    layout(barmode = &quot;overlay&quot;) %>% 
    highlight(&quot;plotly_selected&quot;, persistent = TRUE)
)</pre>

<p><a rel="nofollow" href="https://blog.cpsievert.me/crosstalk-aggregates.html" target="_blank"><br>
<img src="https://i2.wp.com/i.imgur.com/3YKx7Ow.gif?w=100%25&ssl=1" data-recalc-dims="1"><br>
</a></p>
<p>If you’re interested in understanding the full power of the linking framework, my <a rel="nofollow" href="https://plotcon.plot.ly/r-shiny-dash-r/" target="_blank">2 day plotly for R workshop</a> is the best way to learn it effectively. I also offer this workshop as an on-site training course, so <a rel="nofollow" href="https://carsonsievert.typeform.com/to/FKUSbW" target="_blank">please get in touch</a> if you have any interest!</p>
</div>
</div>
<div>
<h2>More learning resources</h2>
<p>At least currently, the best examples of using <strong>sf</strong> with <strong>plotly</strong> are within the package demos. Any demo names that are prefixed with ‘sf’ when you look at the list provided by <code>demo(package = &quot;plotly&quot;)</code> are relevant. For example, <code>demo(&quot;sf-dt&quot;, package = &quot;plotly&quot;)</code> gives an example of querying simple feature data by linking <code>plot_mapbox()</code> with <strong>DT</strong> via <strong>crosstalk</strong>. Also be on the look-out for updates to the <a rel="nofollow" href="https://plotly-book.cpsievert.me/maps.html" target="_blank">mapping section</a> of the <a rel="nofollow" href="https://plotly-book.cpsievert.me/" target="_blank">plotly for R</a> book as well as examples in some of my more recent <a rel="nofollow" href="https://talks.cpsievert.me/" target="_blank">talks</a>.</p>
</div>
<div>
<h2>Future work</h2>
<p>I’m excited to see the author of <strong>sf</strong>, Edzer Pebesma, starting work on <a rel="nofollow" href="https://github.com/r-spatial/stars" target="_blank"><strong>stars</strong></a> – a tidy (and <strong>sf</strong> friendly) approach to working with geo-spatial arrays (e.g. raster data). Once that project becomes stable, I’m hoping to find the time and resources to <a rel="nofollow" href="https://github.com/ropensci/plotly/issues/1200" target="_blank">build a similar bridge</a> between <strong>plotly</strong> and <strong>stars</strong>. This effort might have to take a back seat for several months though unless someone would like to <a rel="nofollow" href="https://plot.ly/products/consulting-and-oem/" target="_blank">sponsor</a> (or otherwise assist in) development.</p>
</div>
<div>
<h2>Appendix: strengths and weaknesses</h2>
<p>Below is a list of strengths (blue) and weaknesses (red) for each mapping approach in <strong>plotly</strong>. Note that plotly.js is still under development, so this list is likely change a bit (please <a rel="nofollow" href="mailto:cpsievert1@gmail.com" target="_blank">let me know</a> if I’m missing anything):</p>
<div>
<h3>1. <code>plot_ly()</code> and <code>geom_sf()</code></h3>
<ul>
<li>Render in SVG or WebGL (<code>toWebGL()</code> makes SVG -> WebGL easy) <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1">
<ul>
<li><code>fill='toself'</code> is <a rel="nofollow" href="https://github.com/plotly/plotly.js/issues/2291" target="_blank">still buggy</a> in WebGL <img alt="🔴" src="https://i1.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f534.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
</ul>
</li>
<li>Make 3D visuals by adding a <code>z</code> attribute <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1">
<ul>
<li>With a bit of math, you can project any lat/lon data onto a sphere (i.e. globe) and color the globe’s surface according to some measure, <a rel="nofollow" href="https://github.com/cpsievert/Weather_Stuff/blob/ba80004/radiation-plot-3D.R#L33-L41" target="_blank">like radiation</a> <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
<li>Unlike 2D lines, 3D lines support a color gradient <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
<li>Using <code>subplot()</code> with 3D <a rel="nofollow" href="https://github.com/ropensci/plotly/issues/711" target="_blank">doesn’t currently rescale domains correctly</a> <img alt="🔴" src="https://i1.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f534.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
</ul>
</li>
<li>Works with any coordinate system <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1">
<ul>
<li>Currently no way to update a graticule on zoom <img alt="🔴" src="https://i1.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f534.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
</ul>
</li>
</ul>
</div>
<div>
<h3>2. <code>plot_mapbox()</code></h3>
<ul>
<li>Full customization of base-maps that provide geo-graphic context <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
<li>Simple features can be rendered as <a rel="nofollow" href="https://github.com/ropensci/plotly/blob/master/demo/sf-mapbox-data.R" target="_blank">data</a> or <a rel="nofollow" href="https://github.com/ropensci/plotly/blob/master/demo/sf-mapbox-layout.R" target="_blank">layout</a> components <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
<li><a rel="nofollow" href="https://github.com/plotly/plotly.js/issues/815" target="_blank">Numerous trace rendering limitations</a> including no <code>marker.line</code> <code>hoveron='fill'</code> (i.e., <code>stroke</code> and <code>span</code> won’t do anything) <img alt="🔴" src="https://i1.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f534.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
<li>WebGL infrastructure allows one to render lots of graphical elements <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
</ul>
</div>
<div>
<h3>3. <code>plot_geo()</code>:</h3>
<ul>
<li>Somewhat customization base-maps provide geo-graphic context <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1">
<ul>
<li>Compared to <code>plot_mapbox()</code>, base-map styling is quite limited <img alt="🔴" src="https://i1.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f534.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
</ul>
</li>
<li>Supports <a rel="nofollow" href="https://en.wikipedia.org/wiki/Orthographic_projection" target="_blank">orthographic</a> (3D) projections as well as a number of other 2D projections <img alt="🔵" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/1f535.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></li>
</ul>
</div>
</div>
<div>
<hr>
<ol>
<li>
<p>I got this idea thanks to <a rel="nofollow" href="https://medium.com/@plotlygraphs/how-to-create-2d-and-3d-interactive-weather-maps-in-python-and-r-77ddd53cca8" target="_blank">this post</a> and <a rel="nofollow" href="https://plot.ly/~empet" target="_blank">plotly user Emilia</a>.<a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fnref1" target="_blank"><img alt="↩" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/21a9.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></a></p>
</li>
<li>
<p>Check for yourself by doing <code>plotly_json(plot_ly(nc))</code>.<a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fnref2" target="_blank"><img alt="↩" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/21a9.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></a></p>
</li>
<li>
<p>The <code>plot_mapbox()</code> builds on <a rel="nofollow" href="https://www.mapbox.com/mapbox-gl-js/api/" target="_blank">mapbox-gl.js</a> which requires an access token. Once you have one, inform <strong>plotly</strong> about your token via <code>Sys.setenv('MAPBOX_TOKEN' = 'secret token')</code> (or via an <code>.Renviron</code> file).<a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fnref3" target="_blank"><img alt="↩" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/21a9.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></a></p>
</li>
<li>
<p>To learn more, read <a rel="nofollow" href="https://plotly-book.cpsievert.me/linking-views-without-shiny.html#the-shareddata-plot-pipeline" target="_blank">https://plotly-book.cpsievert.me/linking-views-without-shiny.html#the-shareddata-plot-pipeline</a><a rel="nofollow" href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/#fnref4" target="_blank"><img alt="↩" src="https://i2.wp.com/s.w.org/images/core/emoji/2.4/72x72/21a9.png?w=456&ssl=1" class="wp-smiley" data-recalc-dims="1"></a></p>
</li>
</ol>
</div>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="https://moderndata.plot.ly/visualizing-geo-spatial-data-with-sf-and-plotly/"> R – Modern Data</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/Qac5-l6gt8s" height="1"></a></div>