<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Carson&#39;s blog on R, RStudio, plotly, shiny, data visualization, statistics, etc</title>
    <link>/index.xml</link>
    <description>Recent content on Carson&#39;s blog on R, RStudio, plotly, shiny, data visualization, statistics, etc</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 11 Apr 2019 00:00:00 +0000</lastBuildDate>
    <atom:link href="/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>plotly 4.9.0 now on CRAN</title>
      <link>/2019/04/11/plotly-4-9-0-now-on-cran.html</link>
      <pubDate>Thu, 11 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>/2019/04/11/plotly-4-9-0-now-on-cran.html</guid>
      <description>

&lt;p&gt;I&amp;rsquo;m excited to announce &lt;strong&gt;plotly&lt;/strong&gt; 4.9.0 is now on CRAN! Go ahead and upgrade via:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;install.packages(&amp;quot;plotly&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This release is about 8 months in the making and includes many &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md#bug-fixes&#34;&gt;bug fixes&lt;/a&gt;, some &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md#new-features--improvements&#34;&gt;new features&lt;/a&gt;, and a couple slightly &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md#changes&#34;&gt;breaking changes&lt;/a&gt;. Over this time, I&amp;rsquo;ve mainly focused on getting a first draft of my new book, &lt;a href=&#34;https://plotly-r.com&#34;&gt;https://plotly-r.com&lt;/a&gt;, and some of these additions to &lt;strong&gt;plotly&lt;/strong&gt; are in support of that new content. This post highlights the most important release features, but I highly recommend going over &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md&#34;&gt;the full release report&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2 id=&#34;new-shiny-events&#34;&gt;New shiny events&lt;/h2&gt;

&lt;p&gt;This release exposes a handful of new plotly events in shiny. &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md#new-features--improvements&#34;&gt;See here&lt;/a&gt; for the full list of new events, &lt;a href=&#34;https://plotly-r.com/linking-views-with-shiny.html#shiny-plotly-inputs&#34;&gt;this section of my book&lt;/a&gt; to learn about how to leverage plotly events in shiny, and my &lt;a href=&#34;https://resources.rstudio.com/webinars/accessing-and-responding-to-plotly-events-in-shiny-carson-sievert&#34;&gt;RStudio webinar&lt;/a&gt; for a tutorial on how to create responsive and scalable crossfiltering applications with these new events (like in the video below).&lt;/p&gt;

&lt;iframe src=&#34;https://player.vimeo.com/video/318129502?title=0&amp;byline=0&amp;portrait=0&#34; width=&#34;640&#34; height=&#34;258&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; fullscreen&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Also, see the &lt;a href=&#34;https://plotly-r.com/linking-views-with-shiny.html#drill-down&#34;&gt;advanced applications section of the plotly book&lt;/a&gt; for some new drill down examples.&lt;/p&gt;

&lt;h2 id=&#34;new-version-of-plotly-js&#34;&gt;New version of plotly.js&lt;/h2&gt;

&lt;p&gt;This new version of the R package upgrades the underlying plotly.js library from v1.42.3 to v1.46.1. This includes many bug fixes and new features, some of which I don&amp;rsquo;t mention here or in the R package&amp;rsquo;s NEWS, but you can see &lt;a href=&#34;https://github.com/plotly/plotly.js/releases&#34;&gt;plotly.js&amp;rsquo; release page&lt;/a&gt; for more info. That being said, here&amp;rsquo;s a breakdown of the most important items:&lt;/p&gt;

&lt;h3 id=&#34;new-trace-types&#34;&gt;New trace types&lt;/h3&gt;

&lt;p&gt;This release includes 3 new trace types: isosurface, sunburst, and waterfall. To get idea of what possible, you can search the plotly.js tests via &lt;a href=&#34;https://rreusser.github.io/plotly-mock-viewer&#34;&gt;https://rreusser.github.io/plotly-mock-viewer&lt;/a&gt; (the corresponding JSON source behind these example can be found &lt;a href=&#34;https://github.com/plotly/plotly.js/tree/master/test/image/mocks&#34;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isosurface&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe src=&#34;https://player.vimeo.com/video/329848156?title=0&amp;byline=0&amp;portrait=0&#34; width=&#34;640&#34; height=&#34;480&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; fullscreen&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;ul&gt;
&lt;li&gt;Sunburst&lt;/li&gt;
&lt;/ul&gt;

&lt;iframe src=&#34;https://player.vimeo.com/video/329850403?title=0&amp;byline=0&amp;portrait=0&#34; width=&#34;640&#34; height=&#34;480&#34; frameborder=&#34;0&#34; allow=&#34;autoplay; fullscreen&#34; allowfullscreen&gt;&lt;/iframe&gt;

&lt;ul&gt;
&lt;li&gt;Waterfall&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;plot_ly() %&amp;gt;%
  add_trace(
    type = &amp;quot;waterfall&amp;quot;,
    x = c(0, 1, 2, 3, 4, 5),
    y = c(1, 0.5, 0.7, -1.2, 0.3, 0.4)
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;./img/waterfall.png&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;

&lt;p&gt;I suspect soon &lt;a href=&#34;https://plot.ly/r&#34;&gt;https://plot.ly/r&lt;/a&gt; will have more R examples of these traces, but for now you can see some examples here&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/tests/testthat/test-plotly-isosurface.R&#34;&gt;https://github.com/ropensci/plotly/blob/master/tests/testthat/test-plotly-isosurface.R&lt;/a&gt;
&lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/tests/testthat/test-plotly-sunburst.R&#34;&gt;https://github.com/ropensci/plotly/blob/master/tests/testthat/test-plotly-sunburst.R&lt;/a&gt;
&lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/tests/testthat/test-plotly-waterfall.R&#34;&gt;https://github.com/ropensci/plotly/blob/master/tests/testthat/test-plotly-waterfall.R&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;new-hovertemplate-attribute&#34;&gt;New hovertemplate attribute&lt;/h2&gt;

&lt;p&gt;One of the more difficult things about &lt;strong&gt;plotly&lt;/strong&gt; and plotly.js is about the various ways to control tooltips. &lt;a href=&#34;https://plotly-r.com/controlling-tooltips.html#tooltip-text&#34;&gt;This new special topic in my book&lt;/a&gt; attempts to cover all these approaches, as well as the new &lt;a href=&#34;https://plot.ly/r/reference/#scatter-hovertemplate&#34;&gt;&lt;code&gt;hovertemplate&lt;/code&gt;&lt;/a&gt; approach. This new attribute allows you to reference supplied (e.g., &lt;code&gt;x&lt;/code&gt; in the Figure below) or computed variables in the tooltip (e.g., &lt;code&gt;y&lt;/code&gt; in the Figure below). It also allows you to control the formatting (using d3-format&amp;rsquo;s syntax &lt;code&gt;%{variable:d3-format}&lt;/code&gt;) and the &lt;code&gt;&amp;lt;extra&amp;gt;&lt;/code&gt; bit of the tooltip that usually displays the trace &lt;code&gt;name&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;plot_ly(x = rnorm(100, 0, 1e5)) %&amp;gt;%
    add_histogram(
        histnorm = &amp;quot;density&amp;quot;,
        hovertemplate = &amp;quot;The density between &amp;lt;br&amp;gt; (%{x}) is %{y:.1e} &amp;lt;extra&amp;gt;That&#39;s very &amp;lt;br&amp;gt; small!&amp;lt;/extra&amp;gt;&amp;quot;
    )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;./img/hovertemplate.png&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;

&lt;h2 id=&#34;new-title-api&#34;&gt;New title API&lt;/h2&gt;

&lt;p&gt;Previously plot title&amp;rsquo;s were created by providing a string to &lt;a href=&#34;https://plot.ly/r/reference/#layout-title&#34;&gt;&lt;code&gt;layout.title&lt;/code&gt;&lt;/a&gt;. This will continue to work, but &lt;code&gt;layout.title&lt;/code&gt; now accepts a list object, which adds the ability to move the title&amp;rsquo;s location.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;library(plotly)
plot_ly(x = 1, y = 1) %&amp;gt;%
  layout(title = 
    list(
      text = &amp;quot;My title&amp;quot;, 
      x = 1, 
      font = list(
        family = &amp;quot;Roboto&amp;quot;, 
        color = &amp;quot;#1E86FF&amp;quot;, 
        size = 18
      )
    )
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;./img/title.svg&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;

&lt;p&gt;Since plotly.js now supports this feature, &lt;code&gt;ggplotly()&lt;/code&gt; will now automatically pick up on the title alignment&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;library(plotly)
p &amp;lt;- qplot(1:10) + 
  ggtitle(&amp;quot;My amazing plot!&amp;quot;) +
  theme(
    plot.title = element_text(
      family = &amp;quot;Roboto&amp;quot;, 
      color = &amp;quot;red&amp;quot;, 
      size = 16
    )
  )
ggplotly(p)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&#34;./img/ggtitle.svg&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Announcing my new book: Interactive web-based data visualization with R, plotly, and shiny</title>
      <link>/2019/04/01/announcing-my-new-book-interactive-web-based-data-visualization-with-r-plotly-and-shiny.html</link>
      <pubDate>Mon, 01 Apr 2019 00:00:00 +0000</pubDate>
      
      <guid>/2019/04/01/announcing-my-new-book-interactive-web-based-data-visualization-with-r-plotly-and-shiny.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://plotly-r.com&#34;&gt;My online book&lt;/a&gt; (previously known as &lt;em&gt;plotly for R&lt;/em&gt;, now titled &lt;em&gt;Interactive web-based data visualization with R, plotly, and shiny&lt;/em&gt;) has received a &lt;strong&gt;major&lt;/strong&gt; update with heaps of new examples and content! &lt;a href=&#34;https://plotly-r.com/plotly_book.pdf&#34;&gt;A print/pdf version&lt;/a&gt; of the book is now under review and should become available in the coming months. In the meantime, please do &lt;a href=&#34;mailto:cpsievert1@gmail.com&#34;&gt;send me feedback&lt;/a&gt; or any comments as I would appreciate your input during the review process!&lt;/p&gt;

&lt;p&gt;For those already somewhat familiar with the book, here is some highlights of the biggest additions and changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A new top-level &lt;a href=&#34;https://plotly-r.com/introduction.html&#34;&gt;Introductory chapter&lt;/a&gt; helping to explain what&amp;rsquo;s in and not in the book.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Chapters are now organized into 6 parts: Creating views, Publishing views, Combining multiple views, Linking multiple view, Custom behavior with JavaScript, and Various special topics.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;The &amp;lsquo;plotly cookbook&amp;rsquo; chapter has expanded into several chapters (Part I: Creating Views), complete with a new &lt;a href=&#34;https://plotly-r.com/overview.html&#34;&gt;Overview Chapter&lt;/a&gt;, a much more complete &lt;a href=&#34;https://plotly-r.com/scatter-traces.html&#34;&gt;Chapter on scatter traces&lt;/a&gt;, and much more on &lt;a href=&#34;https://plotly-r.com/maps.html&#34;&gt;mapping functionality&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Lots of new examples and documentation of &lt;strong&gt;plotly&lt;/strong&gt;&amp;rsquo;s ability to &lt;a href=&#34;https://plotly-r.com/client-side-linking.html&#34;&gt;link views client-side&lt;/a&gt; as well as &lt;a href=&#34;https://plotly-r.com/linking-server-side.html&#34;&gt;server-side with &lt;strong&gt;shiny&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Lots of new examples and documentation about writing custom event handlers in &lt;code&gt;JavaScript&lt;/code&gt; (see Part V: Custom behavior with &lt;code&gt;JavaScript&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Updated examples and writing in the Chapters &lt;a href=&#34;https://plotly-r.com/arranging-views.html&#34;&gt;Arranging views&lt;/a&gt; and &lt;a href=&#34;https://plotly-r.com/animating-views.html&#34;&gt;Animating views&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Part VI includes a handful of new topics addressing functionality that currently isn&amp;rsquo;t well documented elsewhere, including everything you need to know about working with &lt;a href=&#34;https://plotly-r.com/controlling-tooltips.html&#34;&gt;tooltips&lt;/a&gt;, &lt;a href=&#34;https://plotly-r.com/working-with-colors.html&#34;&gt;colors&lt;/a&gt;, &lt;a href=&#34;https://plotly-r.com/working-with-symbols.html&#34;&gt;symbols&lt;/a&gt;, the &lt;a href=&#34;https://plotly-r.com/control-modebar.html&#34;&gt;modebar&lt;/a&gt;, and more!&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;A new &lt;a href=&#34;https://bit.ly/plotly-book-cloud&#34;&gt;RStudio cloud project&lt;/a&gt; for running the code examples in the book.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Some of this content assumes you are running the development version of a few packages, so if you want to run the code examples locally, you can install all the packages (and their correct versions) with:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-r&#34;&gt;remotes::install_github(&amp;quot;cpsievert/plotly_book&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>plotly 4.8.0 now on CRAN</title>
      <link>/2018/07/18/plotly-4-8-0-now-on-cran.html</link>
      <pubDate>Wed, 18 Jul 2018 00:00:00 +0000</pubDate>
      
      <guid>/2018/07/18/plotly-4-8-0-now-on-cran.html</guid>
      <description>&lt;p style=&#34;background-color: #f5f5f5; border-left-width: 10px; border-left-style: solid; border-left-color: #CBF8DF;&#34;&gt;
&lt;b&gt;
Need help with R, plotly, data viz, and/or stats? &lt;a href=&#34;https://consulting.cpsievert.me&#34;&gt;Work with me&lt;/a&gt;!
&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;I’m super excited to announce &lt;strong&gt;plotly&lt;/strong&gt; 4.8.0 is now on CRAN! Go ahead and upgrade via:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;install.packages(&amp;quot;plotly&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This release is almost a year in the making and includes a huge amount of improvements, new features, and some slightly breaking changes. This post highlights the biggest and most recent features; but if you already use &lt;strong&gt;plotly&lt;/strong&gt;, I highly recommend going over &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md&#34;&gt;the full release report&lt;/a&gt; as well.&lt;/p&gt;
&lt;div id=&#34;new-trace-types&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;New trace types&lt;/h2&gt;
&lt;p&gt;Upgrading &lt;strong&gt;plotly&lt;/strong&gt; from 4.7.1 to 4.8.0 implies an upgrade of plotly.js from 1.29.2 to 1.39.2. This means, amongst many other things, seven new trace types. Here’s a list with a link to their relevant online &lt;a href=&#34;https://plot.ly/r&#34; class=&#34;uri&#34;&gt;https://plot.ly/r&lt;/a&gt; documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://plot.ly/r/violin/&#34;&gt;Violin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;3D &lt;a href=&#34;https://plot.ly/r/3d-cone/&#34;&gt;cones&lt;/a&gt; and &lt;a href=&#34;https://plot.ly/r/streamtube-plot/&#34;&gt;streamtubes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plot.ly/r/polar-chart/&#34;&gt;New and improved SVG &amp;amp; WebGL polar charts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://plot.ly/r/splom/&#34;&gt;Scatterplot matrices&lt;/a&gt; (NOTE: click “Box select” in the modebar of these examples for linked brushing!)&lt;/li&gt;
&lt;li&gt;Tables (NOTE: the new &lt;code&gt;add_table()&lt;/code&gt; function makes it easier to map a data frame to this trace type)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;improved-static-image-export&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Improved static image export&lt;/h2&gt;
&lt;p&gt;The new &lt;code&gt;orca()&lt;/code&gt; function wraps the new &lt;a href=&#34;https://github.com/plotly/orca&#34;&gt;orca project&lt;/a&gt; for killer exporting of plotly graphs, dashboards, etc to various formats (most notably, svg and pdf!). Simply give &lt;code&gt;orca()&lt;/code&gt; a &lt;strong&gt;plotly&lt;/strong&gt; object and a filename with the extension that you desire. Here’s an example of exporting to SVG and post-processing the result in Adobe Illustrator:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &amp;lt;- plot_ly(z = ~volcano) %&amp;gt;% add_surface()
orca(p, &amp;quot;surface-plot.svg&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://i.imgur.com/Wu1TQaE.gif&#34; width=&#34;100%&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;auto-margins&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Auto margins&lt;/h2&gt;
&lt;p&gt;Axis objects now default to &lt;code&gt;automargin = TRUE&lt;/code&gt;. This helps the axis labels of any &lt;strong&gt;plotly&lt;/strong&gt; graph to be more readable by default:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(plotly)
library(dplyr)

# plot the number of missing values by city
txhousing %&amp;gt;% 
  group_by(city) %&amp;gt;% 
  summarise(missing = sum(is.na(median))) %&amp;gt;% 
  filter(missing &amp;gt; 0) %&amp;gt;%
  plot_ly(
    x = ~missing, 
    y = ~forcats::fct_reorder(city, missing)
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://i.imgur.com/9hkTLUU.png&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;
&lt;p&gt;To get the old behavior back, you can set &lt;code&gt;automargin = FALSE&lt;/code&gt;. This hopefully won’t be needed except in extreme edge cases:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;layout(.Last.value, yaxis = list(automargin = FALSE))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://i.imgur.com/K8jEseM.png&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;localization-support&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Localization support&lt;/h2&gt;
&lt;p&gt;The new &lt;code&gt;locale&lt;/code&gt; argument in the &lt;code&gt;config()&lt;/code&gt; function makes it easy to switch the language used for date axes and on-graph text (e.g., modebar buttons). This example demonstrates Japanese (&lt;code&gt;&amp;quot;ja&amp;quot;&lt;/code&gt;) – see &lt;code&gt;?config&lt;/code&gt; for more examples and documentation of other locales.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;today &amp;lt;- Sys.Date()
x &amp;lt;- seq.Date(today, today + 360, by = &amp;quot;day&amp;quot;)
plot_ly(x = x, y = rnorm(length(x))) %&amp;gt;%
  add_lines() %&amp;gt;%
  config(locale = &amp;quot;ja&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://i.imgur.com/8nYv98Z.png&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;partial-plotly.js-bundles&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Partial plotly.js bundles&lt;/h2&gt;
&lt;p&gt;By default, the R package ships with a &lt;em&gt;full&lt;/em&gt; bundle of plotly.js, which is quite large (about 2.6 MB in this release). In many cases, graphs can be rendered with a &lt;a href=&#34;https://github.com/plotly/plotly.js/tree/master/dist#partial-bundles&#34;&gt;partial plotly.js bundle&lt;/a&gt;, which can lead to a 3x reduction in file size! To take advantage, just apply the &lt;code&gt;partial_bundle()&lt;/code&gt; function to a &lt;strong&gt;plotly&lt;/strong&gt; object, which (by default) will try and find a suitable bundle.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(plotly)
p &amp;lt;- plot_ly(x = 1:10, y = 1:10) %&amp;gt;% add_markers()
save_widget &amp;lt;- function(p, f) {
  owd &amp;lt;- setwd(dirname(f))
  on.exit(setwd(owd))
  htmlwidgets::saveWidget(p, f)
  mb &amp;lt;- round(file.info(f)$size / 1e6, 3)
  message(&amp;quot;File is: &amp;quot;, mb,&amp;quot; MB&amp;quot;)
}
f1 &amp;lt;- tempfile(fileext = &amp;quot;.html&amp;quot;)
save_widget(p, f1)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#&amp;gt; File is: 2.94 MB&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;f2 &amp;lt;- tempfile(fileext = &amp;quot;.html&amp;quot;)
save_widget(partial_bundle(p), f2)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#&amp;gt; File is: 0.973 MB&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;new-and-improved-webgl-renderer&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;New and improved WebGL renderer&lt;/h2&gt;
&lt;p&gt;For a while now, we’ve had the ability to switch from SVG to WebGL via the function &lt;code&gt;toWebGL()&lt;/code&gt;, which can improve performance when rendering lots of graphical elements. Now there is even more reason to do so as the new WebGL renderer is now &lt;a href=&#34;https://github.com/plotly/plotly.js/issues/130&#34;&gt;much closer to being feature complete&lt;/a&gt; with the SVG renderer.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(x = rnorm(1e6), y = rnorm(1e6)) %&amp;gt;%
  add_markers(color = I(&amp;quot;transparent&amp;quot;), stroke = I(&amp;quot;black&amp;quot;), span = I(1)) %&amp;gt;%
  toWebGL()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://i.imgur.com/MfRuqER.gif&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;mathjax-support&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;MathJax support&lt;/h2&gt;
&lt;p&gt;LaTeX rendering via MathJax is now possible via the new &lt;code&gt;TeX()&lt;/code&gt; function may be used to flag a character vector as LaTeX. To load MathJaX externally (meaning an internet connection is needed for TeX rendering), set the new &lt;code&gt;mathjax&lt;/code&gt; argument in &lt;code&gt;config()&lt;/code&gt; to &lt;code&gt;&amp;quot;cdn&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(plotly)

plot_ly() %&amp;gt;%
  add_lines(x = zoo::index(co2), y = co2) %&amp;gt;%
  layout(
    title = TeX(&amp;quot;CO_2 \\text{measured in } \\frac{parts}{million}&amp;quot;),
    xaxis = list(title = &amp;quot;Time&amp;quot;),
    yaxis = list(title = TeX(&amp;quot;\\text{Atmospheric concentraion of CO}_2&amp;quot;))
  ) %&amp;gt;%
  config(mathjax = &amp;quot;cdn&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use a local version of MathJax (so that your graphs will render without an internet connection), you need to inform &lt;strong&gt;plotly&lt;/strong&gt; where it’s located. If you don’t already have MathJax locally, I recommend downloading the official MathJax git repo. Here’s how to do that using terminal commands:&lt;/p&gt;
&lt;pre class=&#34;shell&#34;&gt;&lt;code&gt;$ git clone https://github.com/mathjax/MathJax.git
$ cd MathJax&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now set the &lt;code&gt;PLOTLY_MATHJAX_PATH&lt;/code&gt; environment variable so that &lt;strong&gt;plotly&lt;/strong&gt; knows where that MathJax folder lives. I recommend setting this variable in you &lt;code&gt;.Rprofile&lt;/code&gt; so you don’t have to reset it everytime you restart R:&lt;/p&gt;
&lt;pre class=&#34;shell&#34;&gt;&lt;code&gt;$ export PLOTLY_MATHJAX_PATH=`pwd`
$ echo &amp;quot;Sys.setenv(&amp;#39;PLOTLY_MATHJAX_PATH&amp;#39; = &amp;#39;$PLOTLY_MATHJAX_PATH&amp;#39;)&amp;quot; &amp;gt;&amp;gt; ~/.Rprofile&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once &lt;code&gt;PLOTLY_MATHJAX_PATH&lt;/code&gt; is set, specify &lt;code&gt;mathjax=&amp;quot;local&amp;quot;&lt;/code&gt; in &lt;code&gt;config()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(plotly)

plotly_empty() %&amp;gt;%
  add_trace(x = 1, y = 1, text = TeX(&amp;quot;\\alpha&amp;quot;), mode = &amp;quot;text&amp;quot;, size = I(100), hoverinfo = &amp;quot;text&amp;quot;) %&amp;gt;%
  config(mathjax = &amp;quot;local&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;mathjax-caveats&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;MathJax caveats&lt;/h3&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;p&gt;At least currently, plotly.js requires SVG-based rendering which doesn’t play nicely with HTML-based rendering (e.g. &lt;strong&gt;rmarkdown&lt;/strong&gt; documents and &lt;strong&gt;shiny&lt;/strong&gt; apps) . If you need both the SVG and HTML rendering, consider &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt;-ing your plotly graph(s) into the larger document (see &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/inst/examples/rmd/MathJax/index.Rmd&#34;&gt;here&lt;/a&gt; for an example).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Due to the size and nature of MathJax, using &lt;code&gt;htmlwidget::saveWidget()&lt;/code&gt; with &lt;code&gt;selfcontained = TRUE&lt;/code&gt; won’t work. At least for now, when you need to save a plotly graph (&lt;code&gt;p&lt;/code&gt;) with local MathJax, do &lt;code&gt;htmlwidget::saveWidget(p, selfcontained = FALSE)&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;other-features-discussed-previously&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Other features discussed previously&lt;/h2&gt;
&lt;p&gt;There are numerous other exciting features that come with this release that I’ve written about previously:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;sf&lt;/strong&gt; support via &lt;code&gt;ggplotly()&lt;/code&gt;, &lt;code&gt;plot_ly()&lt;/code&gt;, &lt;code&gt;plot_geo()&lt;/code&gt;, and &lt;code&gt;plot_mapbox()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Better control over the stroke (i.e., outline) appearance of various filled graphical marks via the new “special arguments” (&lt;code&gt;stroke&lt;/code&gt;, &lt;code&gt;strokes&lt;/code&gt;, &lt;code&gt;alpha_stroke&lt;/code&gt;, &lt;code&gt;span&lt;/code&gt;, and &lt;code&gt;spans&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Read more at:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://blog.cpsievert.me/2018/01/30/learning-improving-ggplotly-geom-sf/&#34; class=&#34;uri&#34;&gt;http://blog.cpsievert.me/2018/01/30/learning-improving-ggplotly-geom-sf/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://blog.cpsievert.me/2018/03/30/visualizing-geo-spatial-data-with-sf-and-plotly/&#34; class=&#34;uri&#34;&gt;http://blog.cpsievert.me/2018/03/30/visualizing-geo-spatial-data-with-sf-and-plotly/&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Visualizing geo-spatial data with sf and plotly</title>
      <link>/2018/03/30/visualizing-geo-spatial-data-with-sf-and-plotly.html</link>
      <pubDate>Fri, 30 Mar 2018 00:00:00 +0000</pubDate>
      
      <guid>/2018/03/30/visualizing-geo-spatial-data-with-sf-and-plotly.html</guid>
      <description>&lt;p style=&#34;background-color: #f5f5f5; border-left-width: 10px; border-left-style: solid; border-left-color: #CBF8DF;&#34;&gt;
&lt;b&gt;
Need help with R, plotly, data viz, and/or stats? &lt;a href=&#34;https://consulting.cpsievert.me&#34;&gt;Work with me&lt;/a&gt;!
&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;In my &lt;a href=&#34;https://blog.cpsievert.me/2018/01/30/learning-improving-ggplotly-geom-sf/&#34;&gt;last post&lt;/a&gt;, we explored interactive visualizations of &lt;a href=&#34;https://r-spatial.github.io/sf/&#34;&gt;simple features&lt;/a&gt; (i.e., interactive maps) via &lt;strong&gt;ggplot2&lt;/strong&gt;’s &lt;code&gt;geom_sf()&lt;/code&gt; and &lt;strong&gt;plotly&lt;/strong&gt;’s &lt;code&gt;ggplotly()&lt;/code&gt;. This time we’ll make similar visualizations using &lt;strong&gt;plotly&lt;/strong&gt;’s “non-ggplot2” mapping interfaces (namely &lt;code&gt;plot_ly()&lt;/code&gt;, &lt;code&gt;plot_geo()&lt;/code&gt;, and &lt;code&gt;plot_mapbox()&lt;/code&gt;). Here’s a quick example of reading a shape file into R as simple features via &lt;a href=&#34;https://r-spatial.github.io/sf/reference/st_read.html&#34;&gt;&lt;code&gt;st_read()&lt;/code&gt;&lt;/a&gt;, then plotting those features (in this case, North Carolina counties) using each one of the four mapping approaches &lt;strong&gt;plotly&lt;/strong&gt; provides. Notice how all of these options auto-magically know how to render simple features:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# to replicate these examples, you currently need the dev version
# devtools::install_github(&amp;#39;ropensci/plotly&amp;#39;)
library(plotly)

nc &amp;lt;- sf::st_read(system.file(&amp;quot;shape/nc.shp&amp;quot;, package = &amp;quot;sf&amp;quot;), quiet = TRUE)
class(nc)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;#&amp;gt; [1] &amp;quot;sf&amp;quot;         &amp;quot;data.frame&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;subplot(nrows = 2,
  ggplot(nc) + geom_sf(),
  plot_ly(nc),
  plot_geo(nc),
  plot_mapbox(nc)
) %&amp;gt;% hide_legend()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./06-sf-options.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/nZujcuv.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You might be wondering, “What can &lt;strong&gt;plotly&lt;/strong&gt; offer over other interactive mapping packages such as &lt;a href=&#34;https://cran.r-project.org/package=leaflet&#34;&gt;&lt;strong&gt;leaflet&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://cran.r-project.org/package=mapview&#34;&gt;&lt;strong&gt;mapview&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://cran.r-project.org/package=mapedit&#34;&gt;&lt;strong&gt;mapedit&lt;/strong&gt;&lt;/a&gt;, etc?”. One big feature is the &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html&#34;&gt;linked brushing framework&lt;/a&gt;, which works best when linking &lt;strong&gt;plotly&lt;/strong&gt; together with other &lt;strong&gt;plotly&lt;/strong&gt; graphs (i.e., only a subset of brushing features are supported when linking to other &lt;a href=&#34;https://rstudio.github.io/crosstalk/widgets.html&#34;&gt;crosstalk-compatible htmlwidgets&lt;/a&gt;). Another is the ability to leverage the &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/&#34;&gt;plotly.js API&lt;/a&gt; to make efficient updates in shiny apps &lt;a href=&#34;https://blog.cpsievert.me/2017/07/13/plotly-4.7.1-now-on-cran/&#34;&gt;via &lt;code&gt;plotlyProxy()&lt;/code&gt;&lt;/a&gt;. Speaking of efficiency, &lt;a href=&#34;https://plot.ly/javascript/&#34;&gt;plotly.js&lt;/a&gt; keeps on improving the performance of their WebGL-based rendering, so I recommend trying &lt;code&gt;plot_ly()&lt;/code&gt; (with &lt;code&gt;toWebGL()&lt;/code&gt;) and/or &lt;code&gt;plot_mapbox()&lt;/code&gt; 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 &lt;a href=&#34;#strengths-weaknesses&#34;&gt;strengths and weaknesses&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Speaking of strengths, plotly.js also has 🌎-class 3D rendering support. When used in combination with &lt;strong&gt;plotly&lt;/strong&gt;’s linking framework, we can do some nifty things – all inside self-contained HTML! For example, &lt;a href=&#34;./sf-plotly-3D-globe.html&#34;&gt;here are linked 3D &amp;amp; 2D views&lt;/a&gt; of tropical storm paths which is useful for querying anomalies and provides some insight into the relationship between distance traveled, altitude, latitude, and longitude:&lt;a href=&#34;#fn1&#34; class=&#34;footnote-ref&#34; id=&#34;fnref1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;!--
[^1]: The long answer is that the scope for interactive graphics libraries, especially a general purpose one, is impossibly large. And, to be completely honest, it bothers me when folks think there is *ever* going to be a single library/solution for interactive graphics. People are quite creative when dreaming up (i.e., requesting) interactive features, which can be good, but also bad, when one insists on a essentially redundant feature(s).
--&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# 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(&amp;quot;sf-plotly-3D-globe&amp;quot;, package = &amp;quot;plotly&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://player.vimeo.com/video/257149623&#34; width=&#34;640&#34; height=&#34;345&#34; frameborder=&#34;0&#34; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;
&lt;/iframe&gt;
&lt;p&gt;As you’ll see in the &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md&#34;&gt;NEWS&lt;/a&gt; of the development version, I’ve also added new &lt;code&gt;stroke&lt;/code&gt; and &lt;code&gt;span&lt;/code&gt; 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 &lt;code&gt;color&lt;/code&gt; and &lt;code&gt;linetype&lt;/code&gt;. In particular, constant values can be specified via &lt;code&gt;I()&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(nc, stroke = I(&amp;quot;#119dff&amp;quot;), span = I(5), color = I(&amp;quot;#00cc96&amp;quot;), linetype = I(&amp;quot;dash&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://i.imgur.com/AEv3EiO.png&#34; width=&#34;100%&#34;/&gt;&lt;/p&gt;
&lt;p&gt;Furthermore, values not wrapped in &lt;code&gt;I()&lt;/code&gt; are mapped to a visual range defined by the plural form of the argument (i.e., &lt;code&gt;strokes&lt;/code&gt; and &lt;code&gt;spans&lt;/code&gt;). However, to effectively map data to these sorts of visuals, we might want to generate mutliple traces.&lt;/p&gt;
&lt;div id=&#34;one-trace-to-rule-them-all&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;One trace to rule them all?&lt;/h2&gt;
&lt;p&gt;One of the trickiest things about &lt;a href=&#34;http://consulting.cpsievert.me/#Training&#34;&gt;mastering &lt;strong&gt;plotly&lt;/strong&gt;&lt;/a&gt; and/or plotly.js is knowing what can and can not be done with just one trace. As I &lt;a href=&#34;https://plotly-book.cpsievert.me/scatter-traces.html#line-plots&#34;&gt;elude to in the &lt;em&gt;plotly for R&lt;/em&gt; book&lt;/a&gt;, 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.&lt;a href=&#34;#fn2&#34; class=&#34;footnote-ref&#34; id=&#34;fnref2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; However, when you need certain scalar (i.e., non-data-array) trace properties (e.g. &lt;code&gt;fillcolor&lt;/code&gt;) to vary, you might want to use &lt;code&gt;split&lt;/code&gt; to create a trace for every level in the &lt;code&gt;split&lt;/code&gt; variable. For example, in this map of &lt;a href=&#34;https://en.wikipedia.org/wiki/First-level_NUTS_of_the_European_Union&#34;&gt;territories&lt;/a&gt; in &lt;a href=&#34;https://en.wikipedia.org/wiki/Franconia&#34;&gt;Franconia&lt;/a&gt;, we ensure one trace per territory (via the &lt;code&gt;split&lt;/code&gt; argument), which leads to two fairly obvious features:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;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 &lt;em&gt;just one trace&lt;/em&gt; via the &lt;a href=&#34;#crosstalk&#34;&gt;crosstalk (i.e. linked views) framework&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A different color for each territory. In this case, we’ve used &lt;code&gt;split&lt;/code&gt; without specifying &lt;code&gt;color&lt;/code&gt;, so plotly.js will impose it’s default coloring rules, but you could easily set a constant color across traces (e.g., &lt;code&gt;color = I(&amp;quot;black&amp;quot;)&lt;/code&gt;) or, as we’ll see shortly, use a custom color scheme.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# load trails data (an sf object bundled with the mapview package)
# install.packages(&amp;#39;mapview&amp;#39;)
data(franconia, package = &amp;quot;mapview&amp;quot;)

# Compare this result with: `plot_ly(franconia, split = ~NAME_ASCI, color = I(&amp;quot;black&amp;quot;))`
plot_ly(franconia, split = ~NAME_ASCI)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./franconia-split.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/83FJOBA.gif&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;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 &lt;code&gt;color&lt;/code&gt; is &lt;em&gt;numeric&lt;/em&gt;, and you want it to set a different fill-color for certain polygon(s), you’ll need &lt;code&gt;split&lt;/code&gt; to ensure there is no more than one color per trace:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(
  franconia, 
  split = ~NUTS_ID,
  color = ~SHAPE_AREA,
  alpha = 1,
  showlegend = FALSE
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./franconia-choro.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/6oFCHiV.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;On the other hand, if &lt;code&gt;color&lt;/code&gt; is a discrete variable, &lt;code&gt;plot_ly()&lt;/code&gt; always produces one trace per level. Since, in this case, there are over 30 districts, I’m going to use &lt;a href=&#34;https://stackoverflow.com/questions/21352683/randomising-qualitative-colours-for-large-sets-in-ggplot&#34;&gt;a color palette&lt;/a&gt; that does a fairly good job in distinguishing between a large number of groups:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;cols &amp;lt;- c(&amp;quot;#89C5DA&amp;quot;, &amp;quot;#DA5724&amp;quot;, &amp;quot;#74D944&amp;quot;, &amp;quot;#CE50CA&amp;quot;, &amp;quot;#3F4921&amp;quot;, &amp;quot;#C0717C&amp;quot;, &amp;quot;#CBD588&amp;quot;, &amp;quot;#5F7FC7&amp;quot;, &amp;quot;#673770&amp;quot;, &amp;quot;#D3D93E&amp;quot;, &amp;quot;#38333E&amp;quot;, &amp;quot;#508578&amp;quot;, &amp;quot;#D7C1B1&amp;quot;, &amp;quot;#689030&amp;quot;, &amp;quot;#AD6F3B&amp;quot;, &amp;quot;#CD9BCD&amp;quot;, &amp;quot;#D14285&amp;quot;, &amp;quot;#6DDE88&amp;quot;, &amp;quot;#652926&amp;quot;, &amp;quot;#7FDCC0&amp;quot;, &amp;quot;#C84248&amp;quot;, &amp;quot;#8569D5&amp;quot;, &amp;quot;#5E738F&amp;quot;, &amp;quot;#D1A33D&amp;quot;, &amp;quot;#8A7C64&amp;quot;, &amp;quot;#599861&amp;quot;)
plot_ly(franconia, color = ~NAME_ASCI, colors = cols, alpha = 1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./franconia-color-discrete.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/LXrGpXx.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Note that you can still &lt;code&gt;color&lt;/code&gt; 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 &lt;code&gt;split&lt;/code&gt; in combination with &lt;code&gt;hoveron = &amp;quot;fill&amp;quot;&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(
  franconia,
  split = ~NUTS_ID,
  color = ~district,
  stroke = I(&amp;quot;black&amp;quot;),
  text = ~paste(NAME_ASCI, &amp;quot;\n is in&amp;quot;, district), 
  hoverinfo = &amp;quot;text&amp;quot;,
  hoveron = &amp;quot;fill&amp;quot;
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./franconia-color-split.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/XqkqQiS.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div id=&#34;leveraging-mapbox-basemaps&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Leveraging mapbox basemaps&lt;/h3&gt;
&lt;p&gt;Among the four mapping options, the one that excites me the most is &lt;code&gt;plot_mapbox()&lt;/code&gt;&lt;a href=&#34;#fn3&#34; class=&#34;footnote-ref&#34; id=&#34;fnref3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;. The primary reason to use &lt;code&gt;plot_mapbox()&lt;/code&gt; (or &lt;code&gt;plot_geo()&lt;/code&gt;) over &lt;code&gt;geom_sf()&lt;/code&gt; (or &lt;code&gt;plot_ly()&lt;/code&gt;) 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 &lt;code&gt;plot_mapbox()&lt;/code&gt; via the &lt;a href=&#34;https://plot.ly/r/reference/#layout-mapbox-style&#34;&gt;&lt;code&gt;layout.mapbox.style&lt;/code&gt; attribute&lt;/a&gt;. In addition to a URL to a &lt;a href=&#34;https://www.mapbox.com/help/create-a-custom-style/&#34;&gt;custom style&lt;/a&gt;, 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 &lt;a href=&#34;https://www.rdocumentation.org/packages/plotly/versions/4.7.1/topics/schema&#34;&gt;&lt;code&gt;schema()&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;styles &amp;lt;- schema()$layout$layoutAttributes$mapbox$style$values
styles&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;[1] &amp;quot;basic&amp;quot;             &amp;quot;streets&amp;quot;           &amp;quot;outdoors&amp;quot;          &amp;quot;light&amp;quot;            
[5] &amp;quot;dark&amp;quot;              &amp;quot;satellite&amp;quot;         &amp;quot;satellite-streets&amp;quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A nice feature to include with these maps is a dropdown to dynamically change the base-map styling. To do so, use the &lt;a href=&#34;https://plot.ly/r/reference/#layout-updatemenus&#34;&gt;&lt;code&gt;layout.updatemenus.buttons&lt;/code&gt; attribute&lt;/a&gt; to control the value of the &lt;code&gt;layout.mapbox.style&lt;/code&gt; attribute. Since we wish to modify the &lt;code&gt;layout.mapbox.style&lt;/code&gt; attribute, which is part of the plot’s layout, we’ll want each dropdown “button” to trigger a &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/&#34;&gt;relayout&lt;/a&gt; event with the appropriate &lt;code&gt;args&lt;/code&gt;. Here is one way to create a list of buttons, one for each of the default styles:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# generate plot.js buttons, one for every style 
style_buttons &amp;lt;- lapply(styles, function(s) {
  list(label = s, method = &amp;quot;relayout&amp;quot;, args = list(&amp;quot;mapbox.style&amp;quot;, s))
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With our list of &lt;code&gt;style_buttons&lt;/code&gt;, we’re now ready to visualize something. Here I’ll leverage the &lt;code&gt;trails&lt;/code&gt; data from the &lt;a href=&#34;https://r-spatial.github.io/mapview/&#34;&gt;&lt;strong&gt;mapview&lt;/strong&gt;&lt;/a&gt; package, which has a number of hiking trails of Franconia, Germany.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data(trails, package = &amp;#39;mapview&amp;#39;)

plot_mapbox(trails, color = I(&amp;quot;black&amp;quot;)) %&amp;gt;%
  layout(
    title = &amp;quot;Selected hiking trails in Franconia&amp;quot;,
    mapbox = list(style = &amp;quot;satellite-streets&amp;quot;),
    updatemenus = list(list(y = 0.8, buttons = rev(style_buttons)))
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./07-satellite.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/YgqpCup.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As a side note, you could also &lt;a href=&#34;https://blog.cpsievert.me/2017/07/13/plotly-4.7.1-now-on-cran/&#34;&gt;use &lt;strong&gt;shiny&lt;/strong&gt; to modify the basemap layer&lt;/a&gt; without redrawing the entire plot, but the result here is self-contained HTML/SVG, which is &lt;strong&gt;much easier&lt;/strong&gt; to share, host, scale, and maintain.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;crosstalk&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Linking views without shiny&lt;/h3&gt;
&lt;p&gt;In terms of linked brushing &lt;em&gt;in self-contained HTML&lt;/em&gt;, &lt;strong&gt;plotly&lt;/strong&gt; is definitely the most advanced &lt;a href=&#34;https://rstudio.github.io/crosstalk/widgets.html&#34;&gt;&lt;strong&gt;crosstalk&lt;/strong&gt;-compatible htmlwidget&lt;/a&gt;. You’ll be able to do more when linking &lt;strong&gt;plotly&lt;/strong&gt; to &lt;strong&gt;plotly&lt;/strong&gt;, but since &lt;a href=&#34;https://github.com/rstudio/DT/pull/498&#34;&gt;persistent selection was recently added to &lt;strong&gt;DT&lt;/strong&gt;&lt;/a&gt;, let’s demonstrate linking &lt;strong&gt;plotly&lt;/strong&gt; with &lt;strong&gt;DT&lt;/strong&gt;. To link views via &lt;strong&gt;crosstalk&lt;/strong&gt;, you’ll want to supply a data frame of interest to the &lt;code&gt;SharedData$new()&lt;/code&gt; 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 &lt;a href=&#34;http://vis.berkeley.edu/papers/generalized_selection/&#34;&gt;generalized selections&lt;/a&gt; (e.g., you could query all trails in a district via &lt;code&gt;SharedData$new(trails, ~district)&lt;/code&gt;).&lt;a href=&#34;#fn4&#34; class=&#34;footnote-ref&#34; id=&#34;fnref4&#34;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; Linking &lt;strong&gt;plotly&lt;/strong&gt; with &lt;strong&gt;DT&lt;/strong&gt; in this way gives us a pretty powerful way to identify simple features both &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html#selection-via-indirect-manipulation&#34;&gt;directly and indirectly&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(crosstalk)
tsd &amp;lt;- SharedData$new(trails)

bscols(
  plot_mapbox(tsd, text = ~FKN, hoverinfo = &amp;quot;text&amp;quot;),
  DT::datatable(tsd)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./08-trails-dt.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/fsxwr5l.gif&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To provide a sneak peak into the power of the linking framework in &lt;strong&gt;plotly&lt;/strong&gt;, 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., &lt;code&gt;add_histogram2d()&lt;/code&gt;, &lt;code&gt;add_boxplot()&lt;/code&gt;, etc). In fact, one could replicate this example with &lt;code&gt;add_bars()&lt;/code&gt; (instead of &lt;code&gt;add_histogram()&lt;/code&gt;) by pre-computing bars heights and &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html#fig:density2scatter&#34;&gt;using a list-column key&lt;/a&gt; to assign multiple counties to each bar. In either case (&lt;code&gt;add_bars()&lt;/code&gt; or &lt;code&gt;add_histogram()&lt;/code&gt;), it is usually a good idea to set &lt;code&gt;layout.barmode = &amp;quot;overlay&amp;quot;&lt;/code&gt; 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., &lt;code&gt;add_histogram()&lt;/code&gt;) it’s also a good idea to also define &lt;code&gt;xbins&lt;/code&gt; (or &lt;code&gt;ybins&lt;/code&gt;) so that binning of new bars use the same rules as the existing (i.e. initial) bars.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ncsd &amp;lt;- SharedData$new(nc)

bscols(
  plot_mapbox(ncsd) %&amp;gt;%
    highlight(dynamic = TRUE, persistent = TRUE),
  plot_ly(ncsd, x = ~AREA) %&amp;gt;% 
    add_histogram(xbins = list(start = 0, end = 0.3, size = 0.02)) %&amp;gt;%
    layout(barmode = &amp;quot;overlay&amp;quot;) %&amp;gt;% 
    highlight(&amp;quot;plotly_selected&amp;quot;, persistent = TRUE)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./crosstalk-aggregates.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/3YKx7Ow.gif&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you’re interested in understanding the full power of the linking framework, my &lt;a href=&#34;https://plotcon.plot.ly/r-shiny-dash-r/&#34;&gt;2 day plotly for R workshop&lt;/a&gt; is the best way to learn it effectively. I also offer this workshop as an on-site training course, so &lt;a href=&#34;https://carsonsievert.typeform.com/to/FKUSbW&#34;&gt;please get in touch&lt;/a&gt; if you have any interest!&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;more-learning-resources&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;More learning resources&lt;/h2&gt;
&lt;p&gt;At least currently, the best examples of using &lt;strong&gt;sf&lt;/strong&gt; with &lt;strong&gt;plotly&lt;/strong&gt; are within the package demos. Any demo names that are prefixed with ‘sf’ when you look at the list provided by &lt;code&gt;demo(package = &amp;quot;plotly&amp;quot;)&lt;/code&gt; are relevant. For example, &lt;code&gt;demo(&amp;quot;sf-dt&amp;quot;, package = &amp;quot;plotly&amp;quot;)&lt;/code&gt; gives an example of querying simple feature data by linking &lt;code&gt;plot_mapbox()&lt;/code&gt; with &lt;strong&gt;DT&lt;/strong&gt; via &lt;strong&gt;crosstalk&lt;/strong&gt;. Also be on the look-out for updates to the &lt;a href=&#34;https://plotly-book.cpsievert.me/maps.html&#34;&gt;mapping section&lt;/a&gt; of the &lt;a href=&#34;https://plotly-book.cpsievert.me&#34;&gt;plotly for R&lt;/a&gt; book as well as examples in some of my more recent &lt;a href=&#34;https://talks.cpsievert.me/&#34;&gt;talks&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;future-work&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Future work&lt;/h2&gt;
&lt;p&gt;I’m excited to see the author of &lt;strong&gt;sf&lt;/strong&gt;, Edzer Pebesma, starting work on &lt;a href=&#34;https://github.com/r-spatial/stars&#34;&gt;&lt;strong&gt;stars&lt;/strong&gt;&lt;/a&gt; – a tidy (and &lt;strong&gt;sf&lt;/strong&gt; 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 &lt;a href=&#34;https://github.com/ropensci/plotly/issues/1200&#34;&gt;build a similar bridge&lt;/a&gt; between &lt;strong&gt;plotly&lt;/strong&gt; and &lt;strong&gt;stars&lt;/strong&gt;. This effort might have to take a back seat for several months though unless someone would like to &lt;a href=&#34;https://plot.ly/products/consulting-and-oem/&#34;&gt;sponsor&lt;/a&gt; (or otherwise assist in) development.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;strengths-weaknesses&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Appendix: strengths and weaknesses&lt;/h2&gt;
&lt;p&gt;Below is a list of strengths (blue) and weaknesses (red) for each mapping approach in &lt;strong&gt;plotly&lt;/strong&gt;. Note that plotly.js is still under development, so this list is likely change a bit (please &lt;a href=&#34;mailto:cpsievert1@gmail.com&#34;&gt;let me know&lt;/a&gt; if I’m missing anything):&lt;/p&gt;
&lt;div id=&#34;plot_ly-and-geom_sf&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;1. &lt;code&gt;plot_ly()&lt;/code&gt; and &lt;code&gt;geom_sf()&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Render in SVG or WebGL (&lt;code&gt;toWebGL()&lt;/code&gt; makes SVG -&amp;gt; WebGL easy) 🔵
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fill=&#39;toself&#39;&lt;/code&gt; is &lt;a href=&#34;https://github.com/plotly/plotly.js/issues/2291&#34;&gt;still buggy&lt;/a&gt; in WebGL 🔴&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Make 3D visuals by adding a &lt;code&gt;z&lt;/code&gt; attribute 🔵
&lt;ul&gt;
&lt;li&gt;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, &lt;a href=&#34;https://github.com/cpsievert/Weather_Stuff/blob/ba80004/radiation-plot-3D.R#L33-L41&#34;&gt;like radiation&lt;/a&gt; 🔵&lt;/li&gt;
&lt;li&gt;Unlike 2D lines, 3D lines support a color gradient 🔵&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;subplot()&lt;/code&gt; with 3D &lt;a href=&#34;https://github.com/ropensci/plotly/issues/711&#34;&gt;doesn’t currently rescale domains correctly&lt;/a&gt; 🔴&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Works with any coordinate system 🔵
&lt;ul&gt;
&lt;li&gt;Currently no way to update a graticule on zoom 🔴&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;plot_mapbox&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;2. &lt;code&gt;plot_mapbox()&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Full customization of base-maps that provide geo-graphic context 🔵&lt;/li&gt;
&lt;li&gt;Simple features can be rendered as &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/demo/sf-mapbox-data.R&#34;&gt;data&lt;/a&gt; or &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/demo/sf-mapbox-layout.R&#34;&gt;layout&lt;/a&gt; components 🔵&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plotly/plotly.js/issues/815&#34;&gt;Numerous trace rendering limitations&lt;/a&gt; including no &lt;code&gt;marker.line&lt;/code&gt; &lt;code&gt;hoveron=&#39;fill&#39;&lt;/code&gt; (i.e., &lt;code&gt;stroke&lt;/code&gt; and &lt;code&gt;span&lt;/code&gt; won’t do anything) 🔴&lt;/li&gt;
&lt;li&gt;WebGL infrastructure allows one to render lots of graphical elements 🔵&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;plot_geo&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;3. &lt;code&gt;plot_geo()&lt;/code&gt;:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Somewhat customization base-maps provide geo-graphic context 🔵
&lt;ul&gt;
&lt;li&gt;Compared to &lt;code&gt;plot_mapbox()&lt;/code&gt;, base-map styling is quite limited 🔴&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Supports &lt;a href=&#34;https://en.wikipedia.org/wiki/Orthographic_projection&#34;&gt;orthographic&lt;/a&gt; (3D) projections as well as a number of other 2D projections 🔵&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&#34;fn1&#34;&gt;&lt;p&gt;I got this idea thanks to &lt;a href=&#34;https://medium.com/@plotlygraphs/how-to-create-2d-and-3d-interactive-weather-maps-in-python-and-r-77ddd53cca8&#34;&gt;this post&lt;/a&gt; and &lt;a href=&#34;https://plot.ly/~empet&#34;&gt;plotly user Emilia&lt;/a&gt;.&lt;a href=&#34;#fnref1&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;&lt;p&gt;Check for yourself by doing &lt;code&gt;plotly_json(plot_ly(nc))&lt;/code&gt;.&lt;a href=&#34;#fnref2&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;&lt;p&gt;The &lt;code&gt;plot_mapbox()&lt;/code&gt; builds on &lt;a href=&#34;https://www.mapbox.com/mapbox-gl-js/api/&#34;&gt;mapbox-gl.js&lt;/a&gt; which requires an access token. Once you have one, inform &lt;strong&gt;plotly&lt;/strong&gt; about your token via &lt;code&gt;Sys.setenv(&#39;MAPBOX_TOKEN&#39; = &#39;secret token&#39;)&lt;/code&gt; (or via an &lt;code&gt;.Renviron&lt;/code&gt; file).&lt;a href=&#34;#fnref3&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;&lt;p&gt;To learn more, read &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html#the-shareddata-plot-pipeline&#34; class=&#34;uri&#34;&gt;https://plotly-book.cpsievert.me/linking-views-without-shiny.html#the-shareddata-plot-pipeline&lt;/a&gt;&lt;a href=&#34;#fnref4&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Learning from and improving upon ggplotly conversions</title>
      <link>/2018/01/30/learning-improving-ggplotly-geom-sf.html</link>
      <pubDate>Tue, 30 Jan 2018 00:00:00 +0000</pubDate>
      
      <guid>/2018/01/30/learning-improving-ggplotly-geom-sf.html</guid>
      <description>&lt;p style=&#34;background-color: #f5f5f5; border-left-width: 10px; border-left-style: solid; border-left-color: #CBF8DF;&#34;&gt;
&lt;b&gt;
Need help with R, plotly, data viz, and/or stats? &lt;a href=&#34;https://consulting.cpsievert.me&#34;&gt;Work with me&lt;/a&gt;!
&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;As the maintainer of the R package &lt;a href=&#34;https://github.com/ropensci/plotly&#34;&gt;&lt;strong&gt;plotly&lt;/strong&gt;&lt;/a&gt;, I’m certainly aware that &lt;code&gt;ggplotly()&lt;/code&gt; is not perfect.&lt;a href=&#34;#fn1&#34; class=&#34;footnote-ref&#34; id=&#34;fnref1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; And, even when conversion from &lt;strong&gt;ggplot2&lt;/strong&gt; to &lt;strong&gt;plotly&lt;/strong&gt; ‘works’ it can leave some things to be desired. For example, it might take a while to render, it might not look exactly the way &lt;strong&gt;ggplot2&lt;/strong&gt; does, and/or the default interactive properties (e.g., tooltips) might not work the way you want them to. In almost every case, these are issues that, with a bit of knowledge about &lt;strong&gt;plotly&lt;/strong&gt; and the underlying &lt;a href=&#34;https://github.com/plotly/plotly.js&#34;&gt;plotly.js&lt;/a&gt; library, you can fix. That’s because, as long as &lt;code&gt;ggplotly()&lt;/code&gt; returns an object, we can inspect its underlying data structure (which, by the way, is useful for learning plotly.js!) and improve on it by modifying that data.&lt;a href=&#34;#fn2&#34; class=&#34;footnote-ref&#34; id=&#34;fnref2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; This post explores several ways to learn from, leverage, and improve &lt;code&gt;ggplotly()&lt;/code&gt; conversions of &lt;strong&gt;ggplot2&lt;/strong&gt;’s &lt;code&gt;geom_sf()&lt;/code&gt; (which is still in development), but some of the same lessons can apply more generally to other &lt;strong&gt;ggplot2&lt;/strong&gt; geoms.&lt;/p&gt;
&lt;div id=&#34;basic-intro-to-geom_sf&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Basic intro to &lt;code&gt;geom_sf()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;For a quick demonstration of &lt;code&gt;geom_sf()&lt;/code&gt;, I’m using &lt;a href=&#34;https://github.com/hrbrmstr/albersusa&#34;&gt;&lt;strong&gt;albersusa&lt;/strong&gt;&lt;/a&gt; to access the &lt;a href=&#34;https://en.wikipedia.org/wiki/Lambert_azimuthal_equal-area_projection&#34;&gt;laea projected&lt;/a&gt; boundaries of the United States as a &lt;a href=&#34;https://cran.r-project.org/web/packages/sf/vignettes/sf1.html&#34;&gt;simple features (sf) data structure&lt;/a&gt;, but &lt;strong&gt;sf&lt;/strong&gt; also makes it easy to &lt;a href=&#34;https://www.rdocumentation.org/packages/sf/versions/0.6-0/topics/st_read&#34;&gt;read various file formats&lt;/a&gt; and even &lt;a href=&#34;https://www.rdocumentation.org/packages/sf/versions/0.6-0/topics/st_as_sf&#34;&gt;convert various spatial objects to &lt;strong&gt;sf&lt;/strong&gt;&lt;/a&gt;. There are also a bunch of other R packages that, like &lt;strong&gt;albersusa&lt;/strong&gt;, make it easy to query geo-spatial data as an &lt;strong&gt;sf&lt;/strong&gt; data. The “Reverse dependencies” section of &lt;a href=&#34;https://cran.r-project.org/package=sf&#34;&gt;sf’s CRAN page&lt;/a&gt; is a good place to discover them, but just to name a few: &lt;a href=&#34;https://cran.r-project.org/package=tidycensus&#34;&gt;&lt;strong&gt;tidycensus&lt;/strong&gt;&lt;/a&gt;, &lt;a href=&#34;https://cran.r-project.org/package=rnaturalearth&#34;&gt;&lt;strong&gt;rnaturalearth&lt;/strong&gt;&lt;/a&gt;, and &lt;a href=&#34;https://cran.r-project.org/package=mapsapi&#34;&gt;&lt;strong&gt;mapsapi&lt;/strong&gt;&lt;/a&gt;. One awesome consequence of using &lt;strong&gt;sf&lt;/strong&gt; is that, since the data structure contains all the geo-spatial information, both &lt;code&gt;plot()&lt;/code&gt; and &lt;code&gt;geom_sf()&lt;/code&gt; just work&lt;sup&gt;&lt;small&gt;TM&lt;/small&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# to replicate these examples, you currently need the dev version
# devtools::install_github(&amp;#39;ropensci/plotly&amp;#39;)
# devtools::install_github(&amp;#39;hrbrmstr/albersusa&amp;#39;)
library(plotly)
library(sf)
library(albersusa)

us_laea &amp;lt;- usa_sf(&amp;quot;laea&amp;quot;)
p &amp;lt;- ggplot(us_laea) + geom_sf()
ggplotly(p)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./01-map.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/nGq1FFi.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The most brilliant thing about &lt;a href=&#34;https://cran.r-project.org/package=sf&#34;&gt;&lt;strong&gt;sf&lt;/strong&gt;&lt;/a&gt; is that it stores &lt;a href=&#34;https://cran.r-project.org/web/packages/sf/vignettes/sf1.html#sfg-simple-feature-geometry&#34;&gt;geo-spatial structures&lt;/a&gt; in a special &lt;a href=&#34;https://jennybc.github.io/purrr-tutorial/ls13_list-columns.html&#34;&gt;list-column&lt;/a&gt; of a data frame. This allows each row to represent the real unit of observation/interest – whether be a polygon, multi-polygon, point, line, or even a collection of these features – and as a result, supports workflows that leverage &lt;a href=&#34;https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html&#34;&gt;tidy-data&lt;/a&gt; principles&lt;a href=&#34;#fn3&#34; class=&#34;footnote-ref&#34; id=&#34;fnref3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In our case, the &lt;code&gt;us_laea&lt;/code&gt; data contains 51 rows (50 states + DC), and the &lt;code&gt;geometry&lt;/code&gt; column tracks info about the geo-spatial objects:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(dplyr)
select(us_laea, name, pop_2014, geometry)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Simple feature collection with 51 features and 2 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -2100000 ymin: -2500000 xmax: 2516374 ymax: 732103.3
epsg (SRID):    NA
proj4string:    +proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 +a=6370997 +b=6370997 +units=m +no_defs
First 10 features:
                   name pop_2014                       geometry
1               Arizona  6731484 MULTIPOLYGON (((-1111066 -8...
2              Arkansas  2966369 MULTIPOLYGON (((557903.1 -1...
3            California 38802500 MULTIPOLYGON (((-1853480 -9...
4              Colorado  5355866 MULTIPOLYGON (((-613452.9 -...
5           Connecticut  3596677 MULTIPOLYGON (((2226838 519...
6  District of Columbia   658893 MULTIPOLYGON (((1960720 -41...
7               Georgia 10097343 MULTIPOLYGON (((1379893 -98...
8              Illinois 12880580 MULTIPOLYGON (((868942.5 -2...
9               Indiana  6596855 MULTIPOLYGON (((1279733 -39...
10            Louisiana  4649676 MULTIPOLYGON (((1080885 -16...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Compared to &lt;a href=&#34;https://gis.stackexchange.com/questions/165974/r-fortify-causing-polygons-to-tear&#34;&gt;older workflows&lt;/a&gt; (e.g., &lt;code&gt;fortify()&lt;/code&gt; + &lt;code&gt;geom_polygon()&lt;/code&gt;), this is a way more convenient and intuitive data structure (especially if your real unit of interest is the state). Moreover, &lt;strong&gt;sf&lt;/strong&gt; tracks additional information about the coordinate system and bounding box which ensures your aspect ratios are always correct and also makes it easy transform and simplify those features (more on this later). It’s worth noting that &lt;strong&gt;sf&lt;/strong&gt; is still very new, and improvements are constantly being made – to keep updated, check out the &lt;a href=&#34;http://r-spatial.org/&#34;&gt;r-spatial&lt;/a&gt; blog.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;tools-for-improving-upon-ggplotly-conversions&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Tools for improving upon &lt;code&gt;ggplotly()&lt;/code&gt; conversions&lt;/h3&gt;
&lt;p&gt;Yes, &lt;code&gt;ggplotly()&lt;/code&gt; converts &lt;a href=&#34;./01-map.html&#34;&gt;the map&lt;/a&gt; ‘correctly’, but it does take a while to print, and for some reason, no tooltip appears when hovering over the map. To investigate why, lets examine the &lt;a href=&#34;https://www.json.org/&#34;&gt;JSON&lt;/a&gt; that &lt;strong&gt;plotly&lt;/strong&gt; sends along to plotly.js to render the map. This can be done via the &lt;code&gt;plotly_json()&lt;/code&gt; function, which is useful for seeing how &lt;em&gt;any&lt;/em&gt; R &lt;strong&gt;plotly&lt;/strong&gt; object is serialized as JSON. This JSON represents what we call a &lt;em&gt;figure&lt;/em&gt;, which is comprised of numerous components – the most important of which are: &lt;em&gt;layout&lt;/em&gt; (for controlling axes, labels, titles, etc) and &lt;em&gt;data&lt;/em&gt; (a collection of &lt;em&gt;traces&lt;/em&gt;, each of which defines a mapping from data to visuals).&lt;a href=&#34;#fn4&#34; class=&#34;footnote-ref&#34; id=&#34;fnref4&#34;&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# prints an interactive htmlwidget if you have listviewer
# install.packages(&amp;#39;listviewer&amp;#39;)
plotly_json(p)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./02-json.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/Lm3qqDX.png&#34; /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;./02-json.html&#34;&gt;Inspecting&lt;/a&gt; the data component, we see that the map contains two &lt;code&gt;&#39;scatter&#39;&lt;/code&gt; traces, both with a mode of &lt;code&gt;&#39;lines&#39;&lt;/code&gt;. The first trace is the &lt;a href=&#34;https://en.wikipedia.org/wiki/Geographic_coordinate_system&#34;&gt;graticule&lt;/a&gt; behind the states and the second trace contains the state outlines which contain over 50,000+ x/y (i.e., lat/lon) positions! This is certainly not the most efficient way to create such a map and there are several ways we could improve upon it without abandoning the comfort of &lt;code&gt;geom_sf()&lt;/code&gt;.&lt;a href=&#34;#fn5&#34; class=&#34;footnote-ref&#34; id=&#34;fnref5&#34;&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; Before we dive into those improvements, lets first consider what happens when &lt;strong&gt;plotly&lt;/strong&gt; generates a plot.&lt;/p&gt;
&lt;p&gt;Whether you’re printing the result of &lt;code&gt;ggplotly()&lt;/code&gt;, &lt;code&gt;plot_ly()&lt;/code&gt;, or generally any R &lt;a href=&#34;http://www.htmlwidgets.org/&#34;&gt;htmlwidget&lt;/a&gt;, there are two main steps that occur: a &lt;em&gt;build&lt;/em&gt; (i.e. compile) and &lt;em&gt;render&lt;/em&gt; step. Roughly speaking, the build step translates R code to an R list. That list is then &lt;a href=&#34;https://en.wikipedia.org/wiki/Serialization&#34;&gt;serialized&lt;/a&gt; as JSON (via &lt;code&gt;jsonlite::toJSON()&lt;/code&gt;) and should match a JSON specification (i.e. schema) defined by the JavaScript library (which uses the JSON to render the widget).&lt;/p&gt;
&lt;p&gt;&lt;img src=&#34;./printing.svg&#34; width=&#34;100%&#34; /&gt;&lt;/p&gt;
&lt;p&gt;If you’ve ever found &lt;code&gt;ggplotly()&lt;/code&gt; slow to print, chances are, the bulk of the time is spent &lt;em&gt;building&lt;/em&gt; the R list and &lt;em&gt;sending&lt;/em&gt; the JSON to plotly.js. For many htmlwidgets, the build time is negligible, but for more complex widgets like &lt;strong&gt;plotly&lt;/strong&gt;, a lot of things need to happen, especially for &lt;code&gt;ggplotly()&lt;/code&gt; since we call &lt;code&gt;ggplot2::ggplot_build()&lt;/code&gt;, then &lt;a href=&#34;https://blog.cpsievert.me/2014/06/01/visualizing-ggplot2-internals-with-shiny-and-d3/&#34;&gt;crawl and map that data structure to plotly.js&lt;/a&gt;. In a &lt;a href=&#34;http://shiny.rstudio.com/&#34;&gt;shiny&lt;/a&gt; app, both the build and render stages are required on initial load, but the new &lt;a href=&#34;https://blog.cpsievert.me/2017/07/13/plotly-4.7.1-now-on-cran&#34;&gt;&lt;code&gt;plotlyProxy()&lt;/code&gt; interface&lt;/a&gt; provides a way to ‘cache’ expensive build (and render!) operation and update a graph by modifying just specific components of the figure (via &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/&#34;&gt;plotly.js functions&lt;/a&gt;). Outside of a ‘reactive context’ like shiny, you could use &lt;code&gt;htmlwidgets::saveWidget()&lt;/code&gt; to ‘cache’ the results of the build step to disk, send the file to someone else (or host it online somewhere), then only the render step is required to view the graph.&lt;/p&gt;
&lt;p&gt;A quick and easy way to try and improve &lt;em&gt;render&lt;/em&gt; performance is to use &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API&#34;&gt;canvas&lt;/a&gt;-based rendering (instead of vector-based SVG) with &lt;code&gt;toWebGL(p)&lt;/code&gt;. Switching from vector to canvas is generally a good idea when dealing with &amp;gt;30,000 vectors, but in this case, we’re only dealing with &lt;a href=&#34;https://i.imgur.com/jc0doQA.png&#34;&gt;a couple hundred vector paths&lt;/a&gt;, so switching from vector to canvas for our map won’t significantly improve rendering performance, and in fact, we’ll lose some nice SVG exclusive features (the plotly.js team is getting close to &lt;a href=&#34;https://github.com/plotly/plotly.js/issues/130&#34;&gt;eliminating these limitations&lt;/a&gt;!). Instead, what we could (and should!) do is reduce the amount of points along to each path (technically speaking, we’ll reduce the complexity of the SVG &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d&#34;&gt;d attribute&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Thankfully, the &lt;strong&gt;sf&lt;/strong&gt; package provides &lt;code&gt;st_simplify()&lt;/code&gt; function that may be used to simplify polygons while still preserving their shape. A bit of trial and error is involved, but the idea is that by increasing the value of the &lt;code&gt;dTolerance&lt;/code&gt; argument, you’ll decrease the number of points required to draw the spatial features. For fun, before simplifying, lets leverage some more &lt;strong&gt;sf&lt;/strong&gt; awesomeness, &lt;code&gt;st_transform()&lt;/code&gt;. This function allows us to transform our features to &lt;em&gt;any&lt;/em&gt; projection via the &lt;a href=&#34;http://proj4.org/&#34;&gt;proj4&lt;/a&gt; standard. Here I’ll transform from laea to &lt;a href=&#34;https://gis.stackexchange.com/a/141588&#34;&gt;lcc&lt;/a&gt;, and in this case, a &lt;code&gt;dTolerance&lt;/code&gt; of &lt;code&gt;10000&lt;/code&gt; simplifies from roughly 50,000 to 2,500 points. On my machine, that cuts the build and render time in half and reduces the HTML/JSON file size from 1.7MB to 125.9KB.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(sf)
us_lcc &amp;lt;- usa_sf(&amp;quot;laea&amp;quot;) %&amp;gt;%
  st_transform(&amp;quot;+proj=lcc +lat_1=33 +lat_2=45 +lat_0=39 +lon_0=-96 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs&amp;quot;) %&amp;gt;%
  st_simplify(TRUE, dTolerance = 10000)
  
plotly_json(ggplot(us_lcc) + geom_sf())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./02-json-b.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/9qd58g8.png&#34; /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now that we’ve simplified the borders, lets look into why there is no hover information. Since &lt;code&gt;hoverinfo=&#39;text&#39;&lt;/code&gt;, plotly.js just shows the &lt;code&gt;text&lt;/code&gt; attribute in the tooltip, but that attribute is blank! It’s blank because, by default, &lt;code&gt;ggplotly()&lt;/code&gt; puts all aesthetic mapping information in the &lt;code&gt;text&lt;/code&gt; field, but we haven’t actually used an aesthetic mapping here (&lt;code&gt;geom_sf()&lt;/code&gt; is weird in that way – it is the only geom that doesn’t require any aesthetics)! We’ll eventually use aesthetic mappings with &lt;code&gt;geom_sf()&lt;/code&gt; to create a &lt;a href=&#34;https://en.wikipedia.org/wiki/Choropleth_map&#34;&gt;choropleth&lt;/a&gt; map, but before we do, lets find out what the other trace attributes are doing (and find other relevant ones).&lt;/p&gt;
&lt;p&gt;If you’re ever wondering what a particular attribute means (e.g., &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, &lt;code&gt;fillcolor&lt;/code&gt;, &lt;code&gt;hoveron&lt;/code&gt;, etc), you can look up the description online by going to &lt;a href=&#34;https://plot.ly/r/reference/#%5Btype%5D-%5Battr%5D&#34; class=&#34;uri&#34;&gt;https://plot.ly/r/reference/#[type]-[attr]&lt;/a&gt; for a specific trace &lt;code&gt;[type]&lt;/code&gt; and attribute &lt;code&gt;[attr]&lt;/code&gt; (e.g. &lt;a href=&#34;https://plot.ly/r/reference/#scatter-fill&#34; class=&#34;uri&#34;&gt;https://plot.ly/r/reference/#scatter-fill&lt;/a&gt;). The online reference is nice, but I prefer to use the &lt;code&gt;schema()&lt;/code&gt; function for a few reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;schema()&lt;/code&gt; provides a bit more information than the online docs (e.g., value types, default values, acceptable ranges, etc).&lt;/li&gt;
&lt;li&gt;The interface makes it a bit easier to traverse and &lt;em&gt;discover&lt;/em&gt; new attributes.&lt;/li&gt;
&lt;li&gt;You can be absolutely sure it matches the version used in the R package (the online docs might use a different – probably older – version).&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;schema()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./03-schema.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/XqbTTFA.png&#34; /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;./03-schema.html&#34;&gt;Go ahead and have a look&lt;/a&gt; under “traces” -&amp;gt; “scatter” -&amp;gt; “attributes”. These are all the attributes that may be used to control the appearance and interactive properties of a scatter trace. I won’t bother going through descriptions (you can see those for yourself by expanding an attribute), but I will demonstrate how we can leverage the &lt;code&gt;style()&lt;/code&gt; function to modify just the state border’s attributes (specifying &lt;code&gt;traces=2&lt;/code&gt; ensures these changes are only applies to the second trace).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;gg &amp;lt;- ggplotly(ggplot(us_lcc) + geom_sf())
style(
  gg, traces = 2, 
  mode = &amp;quot;markers+lines&amp;quot;,
  hoverinfo = &amp;quot;x+y&amp;quot;, 
  fillcolor = &amp;quot;transparent&amp;quot;,
  hoverlabel = list(bgcolor = &amp;quot;white&amp;quot;)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./01-map-modified.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/1l6IMab.png&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;leveraging-plotlys-interactive-features&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Leveraging plotly’s interactive features&lt;/h3&gt;
&lt;p&gt;After that deep dive into how &lt;code&gt;ggplotly()&lt;/code&gt; works under the hood, and tips for improving rendering performance, let’s explore some lesser known, yet powerful &lt;code&gt;ggplotly()&lt;/code&gt; features. As a side note, anything that can be done via &lt;code&gt;ggplotly()&lt;/code&gt;, you can also do via &lt;code&gt;plot_ly()&lt;/code&gt; (but not necessarily the other way round!) – it just might be more effort to do so. And, sometimes this extra effort is worth it, because &lt;code&gt;ggplotly()&lt;/code&gt; isn’t really designed to be re-sized without being re-printed (&lt;a href=&#34;mailto:cpsievert1@gmail.com&#34;&gt;get in touch&lt;/a&gt; if you want to help us solve this and &lt;a href=&#34;https://github.com/ropensci/plotly/issues/799&#34;&gt;other big issues&lt;/a&gt;). In fact, a lot of times, I prototype plots with &lt;code&gt;ggplotly()&lt;/code&gt;, then translate it &lt;code&gt;plot_ly()&lt;/code&gt; when it’s time to put it into production.&lt;/p&gt;
&lt;div id=&#34;customizing-tooltips&#34; class=&#34;section level4&#34;&gt;
&lt;h4&gt;Customizing tooltips&lt;/h4&gt;
&lt;p&gt;At this point, we’ve learned how to turn a tooltip on/off (via &lt;code&gt;hoverinfo&lt;/code&gt;), but perhaps more useful is the ability to completely control what appears in the tooltip. By using &lt;code&gt;ggplotly()&lt;/code&gt;’s ability to translate a special &lt;code&gt;text&lt;/code&gt; aesthetic with &lt;code&gt;tooltip=&#39;text&#39;&lt;/code&gt;, we can effectively supply any text we want and even style it with HTML tags – as is done in this &lt;a href=&#34;https://en.wikipedia.org/wiki/Choropleth_map&#34;&gt;choropleth map&lt;/a&gt; encoding population in 2014.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &amp;lt;- ggplot(us_lcc) + 
  geom_sf(aes(fill = pop_2014, text = paste(&amp;quot;The state of &amp;lt;b&amp;gt;&amp;quot;, name, &amp;quot;&amp;lt;/b&amp;gt; had \n&amp;quot;, pop_2010, &amp;quot;people in 2010&amp;quot;)))
p %&amp;gt;%
  ggplotly(tooltip = &amp;quot;text&amp;quot;) %&amp;gt;%
  style(hoverlabel = list(bgcolor = &amp;quot;white&amp;quot;), hoveron = &amp;quot;fill&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./01-map-tooltip.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/2T6X3Ec.gif&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;animation&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Animation&lt;/h3&gt;
&lt;p&gt;A choropleth map of the population in 2014 is not that interesting, so let’s grab some other data. Here I download &lt;a href=&#34;http://ghdx.healthdata.org/record/united-states-physical-activity-and-obesity-prevalence-county-2001-2011&#34;&gt;physical activity and obesity ‘prevalence’&lt;/a&gt; between 2001-2011 in every US county from the &lt;a href=&#34;http://ghdx.healthdata.org/&#34;&gt;Global Health Data Exchange&lt;/a&gt;. then finding the mean rate for every combination of state and year:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;url &amp;lt;- &amp;quot;http://ghdx.healthdata.org/sites/default/files/record-attached-files/IHME_USA_OBESITY_PHYSICAL_ACTIVITY_2001_2011.csv&amp;quot;

library(tidyr)
# reshape and create a column tracking the year
dat_clean &amp;lt;- readr::read_csv(url) %&amp;gt;%
  gather(year, value, matches(&amp;quot;prevalence [0-9]+ \\(%\\)&amp;quot;)) %&amp;gt;%
  mutate(year = stringr::str_extract(year, &amp;quot;[0-9]+&amp;quot;)) 

# compute mean outcome for every combination of state/year/outcome
dat_state &amp;lt;- dat_clean %&amp;gt;%
  rename(name = State, outcome = Outcome) %&amp;gt;%
  group_by(name, year, outcome) %&amp;gt;%
  summarise(value = mean(value, na.rm = TRUE))

# attach our (simplified) state features to our summaries 
dat_sf &amp;lt;- dat_state %&amp;gt;%
  left_join(us_lcc) %&amp;gt;%
  st_as_sf() %&amp;gt;%
  mutate(txt = paste(name, year, &amp;quot;\n&amp;quot;, outcome, scales::percent(value / 100)))
  
select(dat_sf, name, year, outcome, value, geometry)&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;Simple feature collection with 1683 features and 4 fields
geometry type:  GEOMETRY
dimension:      XY
bbox:           xmin: -2553435 ymin: -1777696 xmax: 2258071 ymax: 1407299
epsg (SRID):    NA
proj4string:    +proj=lcc +lat_1=33 +lat_2=45 +lat_0=39 +lon_0=-96 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs
# A tibble: 1,683 x 5
# Groups:   name, year [561]
   name    year  outcome       value                       geometry
   &amp;lt;chr&amp;gt;   &amp;lt;chr&amp;gt; &amp;lt;chr&amp;gt;         &amp;lt;dbl&amp;gt;              &amp;lt;sf_geometry [m]&amp;gt;
 1 Alabama 2001  Any PA         66.0 MULTIPOLYGON (((761196.5 -9...
 2 Alabama 2001  Obesity        34.5 MULTIPOLYGON (((761196.5 -9...
 3 Alabama 2001  Sufficient PA  42.7 MULTIPOLYGON (((761196.5 -9...
 4 Alabama 2002  Any PA         66.8 MULTIPOLYGON (((761196.5 -9...
 5 Alabama 2002  Obesity        35.4 MULTIPOLYGON (((761196.5 -9...
 6 Alabama 2002  Sufficient PA NaN   MULTIPOLYGON (((761196.5 -9...
 7 Alabama 2003  Any PA         67.5 MULTIPOLYGON (((761196.5 -9...
 8 Alabama 2003  Obesity        36.2 MULTIPOLYGON (((761196.5 -9...
 9 Alabama 2003  Sufficient PA  44.6 MULTIPOLYGON (((761196.5 -9...
10 Alabama 2004  Any PA         67.7 MULTIPOLYGON (((761196.5 -9...
# ... with 1,673 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s a number of ways we could try to visualize how physical activity and/or obesity has evolved over the years. One way would be to create a small multiple display (one for every year via &lt;code&gt;facet_wrap(~ year)&lt;/code&gt;), but it’s a bit less visual work to perceive differences via animation. Creating animations with &lt;code&gt;ggplotly()&lt;/code&gt; is very similar to &lt;a href=&#34;https://github.com/dgrtwo/gganimate&#34;&gt;gganimate&lt;/a&gt; – we just add an aesthetic mapping of &lt;code&gt;frame = year&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;obesity &amp;lt;- filter(dat_sf, outcome == &amp;quot;Obesity&amp;quot;)
p &amp;lt;- ggplot(obesity) + 
    geom_sf(aes(fill = value, frame = year, text = txt)) + 
    ggtitle(&amp;quot;Obesity rates in the US over time&amp;quot;) +
    ggthemes::theme_map()
plotly_json(p)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./04-frame-json.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/12GzPtx.png&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Having a look at the &lt;a href=&#34;./04-frame-json.html&#34;&gt;underlying JSON&lt;/a&gt; reveals a special &lt;em&gt;frame&lt;/em&gt; component which adheres to the underlying &lt;a href=&#34;https://plot.ly/javascript/#animations&#34;&gt;plotly.js animation api&lt;/a&gt;. It turns out that the data supplied to each frame of the animation has a bunch of redundant information. Specifically, the x/y coordinates for the state boundaries are repeated on every frame – which we don’t really need to do in this case, so let’s remove that data before printing:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# ggplotly() won&amp;#39;t (for good reason) &amp;quot;register&amp;quot; an animation
# until print time, so to acess/modify the frames component, 
# you&amp;#39;ll need plotly_build() -- use this function when you 
# want to be *absolutely* sure you&amp;#39;re accessing the full list/JSON
gg &amp;lt;- p %&amp;gt;%
  ggplotly(tooltip = &amp;quot;text&amp;quot;) %&amp;gt;%
  style(hoveron = &amp;quot;fill&amp;quot;) %&amp;gt;%
  plotly_build()

# remove x/y data from every trace
gg$x$frames &amp;lt;- lapply(
  gg$x$frames, function(f) { 
    f$data &amp;lt;- lapply(f$data, function(d) d[!names(d) %in% c(&amp;quot;x&amp;quot;, &amp;quot;y&amp;quot;)])
    f 
  })
gg&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;./04-animation.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/xg86bkG.gif&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;highlighting&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Highlighting&lt;/h3&gt;
&lt;p&gt;In addition to animation, plotly has powerful framework for filtering, highlighting, and &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html&#34;&gt;linking views without shiny&lt;/a&gt;. This framework leverages the &lt;code&gt;SharedData&lt;/code&gt; class from &lt;a href=&#34;https://rstudio.github.io/crosstalk/&#34;&gt;&lt;strong&gt;crosstalk&lt;/strong&gt;&lt;/a&gt; package where one essentially defines a “unit of interaction” using a column from the data to be visualized. In our case, we can set &lt;code&gt;name&lt;/code&gt; (i.e, state) as the interaction unit, then when we trigger a selection (e.g., brush a time series of physical actively), the relevant graphical marks are highlighted in every view:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;./05-obesity-linked.html&#34; target=&#34;_blank&#34;&gt;
&lt;img src=&#34;https://i.imgur.com/LhxTonw.gif&#34; width=&#34;100%&#34;/&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(crosstalk)
dat_shared &amp;lt;- dat_sf %&amp;gt;%
  filter(!is.na(value)) %&amp;gt;%
  SharedData$new(~name, &amp;quot;A&amp;quot;)

p &amp;lt;- ggplot(dat_shared) + 
  geom_line(aes(x = year, y = value, group = name)) + 
  facet_wrap(~outcome, scales = &amp;quot;free&amp;quot;) +
  theme_bw()

lines &amp;lt;- p %&amp;gt;%
  ggplotly(tooltip = &amp;quot;name&amp;quot;) %&amp;gt;%
  style(mode = &amp;quot;markers+lines&amp;quot;) %&amp;gt;%
  layout(dragmode = &amp;quot;select&amp;quot;) %&amp;gt;%
  highlight(&amp;quot;plotly_selected&amp;quot;)

# compute mean obesity for each state, define &amp;quot;state&amp;quot; as interaction unit (in group &amp;quot;A&amp;quot;)
ob_mean &amp;lt;- obesity %&amp;gt;%
  group_by(name) %&amp;gt;%
  summarise(mean_obesity = mean(value)) %&amp;gt;%
  mutate(txt = paste(name, &amp;quot;mean \n obesity&amp;quot;, scales::percent(mean_obesity / 100))) %&amp;gt;%
  SharedData$new(~name, &amp;quot;A&amp;quot;)

map &amp;lt;- ggplot(ob_mean) + 
  geom_sf(aes(fill = mean_obesity, text = txt)) + 
  ggthemes::theme_map()

library(htmltools)
browsable(tagList(ggplotly(map, tooltip = &amp;quot;text&amp;quot;), lines))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a gentle overview of the linking framework, checkout &lt;a href=&#34;https://vimeo.com/214301880&#34;&gt;my webinar&lt;/a&gt; from when it was initially released. If you’re interested in understanding the full power of the linking framework, my &lt;a href=&#34;https://plotcon.plot.ly/r-shiny-dash-r/&#34;&gt;2 day plotly for R workshop&lt;/a&gt; is the best way to learn it effectively. I also offer this workshop as an on-site training course, so &lt;a href=&#34;https://carsonsievert.typeform.com/to/FKUSbW&#34;&gt;please get in touch&lt;/a&gt; if you have any interest!&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;discussion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Discussion&lt;/h2&gt;
&lt;p&gt;Compared to other interactive mapping approaches, using &lt;code&gt;geom_sf()&lt;/code&gt; + &lt;code&gt;ggplotly()&lt;/code&gt; has it’s pros and its cons. It terms of it’s ability to link multiple views, it seems to be the most advanced, but there are a number of other features you might want (e.g., dynamic zooming of different baselayers). I think a good number of these can be resolved by using &lt;strong&gt;sf&lt;/strong&gt; with &lt;a href=&#34;https://plot.ly/r/scattermapbox/&#34;&gt;&lt;code&gt;plot_mapbox()&lt;/code&gt;&lt;/a&gt; and better support for that should be coming soon, but it would also be nice to see &lt;strong&gt;leaflet&lt;/strong&gt; &lt;a href=&#34;https://github.com/rstudio/leaflet/pull/346&#34;&gt;officially&lt;/a&gt; &lt;a href=&#34;https://github.com/rstudio/leaflet/pull/391&#34;&gt;support&lt;/a&gt; more of the highlighting features that &lt;strong&gt;plotly&lt;/strong&gt; does.&lt;/p&gt;
&lt;p&gt;As it turns out, &lt;strong&gt;plotly&lt;/strong&gt;’s ‘highlighting’ framework can actually be used to do much more than just highlighting. It works by adding additional traces that reflect the selected data and the attributes of these trace(s) can be customized. When used in clever ways, that capability can be used to, for example, &lt;a href=&#34;https://gist.github.com/cpsievert/eca3ff3eba67ab6b4719c748dafd5c4a&#34;&gt;outline simple features&lt;/a&gt; on hover, or even &lt;a href=&#34;https://gist.github.com/cpsievert/fa56bd89122e395803f30602b774dbe1&#34;&gt;click on a simple feature to label&lt;/a&gt; it:
&lt;a href=&#34;https://gist.github.com/cpsievert/fa56bd89122e395803f30602b774dbe1&#34;&gt;
&lt;img src=&#34;https://cloud.githubusercontent.com/assets/1365941/25501881/f816c3d8-2b59-11e7-98e1-fcd94877d584.gif&#34; width=&#34;100%&#34; /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope this post convinces folks that even when a &lt;code&gt;ggplotly()&lt;/code&gt; conversion doesn’t quite work the way you want it to, we can still leverage the underlying &lt;a href=&#34;https://plot.ly/javascript/&#34;&gt;plotly.js library&lt;/a&gt; to do powerful things quickly. My goal for the R package &lt;strong&gt;plotly&lt;/strong&gt; has always been to make interactive web graphics &lt;a href=&#34;https://talks.cpsievert.me/20180202/&#34;&gt;practically useful for exploratory data analysis&lt;/a&gt; in R. If you’re interested in supporting a particular facet of this mission, &lt;a href=&#34;mailto:cpsievert1@gmail.com&#34;&gt;please get in touch&lt;/a&gt; (it’s much easier for plotly to monetize plotly.js and &lt;a href=&#34;https://plot.ly/dash&#34;&gt;dash&lt;/a&gt;, which is why R plotly development has dwindled recently).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&#34;fn1&#34;&gt;&lt;p&gt;I still believe supporting ~99% of the ggplot2 API is achievable (we’re currently at about 80%), but we don’t have the funding/bandwidth for it currently. If you have any interest at all in supporting this effort, please &lt;a href=&#34;mailto:cpsievert1@gmail.com&#34;&gt;get in touch&lt;/a&gt;.&lt;a href=&#34;#fnref1&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;&lt;p&gt;I’ve already &lt;a href=&#34;https://plotly-book.cpsievert.me/extending-ggplotly.html&#34;&gt;written a bit about how this idea&lt;/a&gt; in the &lt;a href=&#34;https://plotly-book.cpsievert.me/&#34;&gt;plotly book&lt;/a&gt;, but I thought I’d make a more detailed guide for this sort of thing.&lt;a href=&#34;#fnref2&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;&lt;p&gt;Jenny Bryan has a &lt;a href=&#34;https://www.youtube.com/watch?v=4MfUCX_KpdE&#34;&gt;superb talk&lt;/a&gt; on leveraging and embracing list-columns.&lt;a href=&#34;#fnref3&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn4&#34;&gt;&lt;p&gt;&lt;code&gt;plotly_json()&lt;/code&gt; also gives one insight into R-specific components, such as &lt;em&gt;highlight&lt;/em&gt; (for controlling &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html&#34;&gt;highlighting options in multiple linked views&lt;/a&gt;) and &lt;em&gt;attrs&lt;/em&gt; (for lazy evaluation of &lt;a href=&#34;https://plotly-book.cpsievert.me/scatter-traces.html&#34;&gt;data -&amp;gt; visual mappings in &lt;code&gt;plot_ly()&lt;/code&gt;&lt;/a&gt;).&lt;a href=&#34;#fnref4&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn5&#34;&gt;&lt;p&gt;&lt;strong&gt;plotly&lt;/strong&gt; offers other “native” mapping options such as &lt;a href=&#34;https://plot.ly/r/scatter-plots-on-maps/&#34;&gt;&lt;code&gt;plot_geo()&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://plot.ly/r/scattermapbox/&#34;&gt;&lt;code&gt;plot_mapbox()&lt;/code&gt;&lt;/a&gt;, which generally speaking are more performant, but they only offer a limited set of projections and/or resolutions (with &lt;code&gt;geom_sf()&lt;/code&gt; you won’t run into the same limitations).&lt;a href=&#34;#fnref5&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Components of a successful R workshop</title>
      <link>/2017/12/04/components-of-a-successful-r-workshop.html</link>
      <pubDate>Mon, 04 Dec 2017 00:00:00 +0000</pubDate>
      
      <guid>/2017/12/04/components-of-a-successful-r-workshop.html</guid>
      <description>&lt;p style=&#34;background-color: #f5f5f5; border-left-width: 10px; border-left-style: solid; border-left-color: #CBF8DF;&#34;&gt;
&lt;b&gt;
Need help with R, plotly, data viz, and/or stats? &lt;a href=&#34;https://consulting.cpsievert.me&#34;&gt;Work with me&lt;/a&gt;!
&lt;/b&gt;
&lt;/p&gt;
&lt;p&gt;I had an absolute blast running &lt;a href=&#34;https://workshops.cpsievert.me/20171118/&#34;&gt;a 2-day R workshop in NYC&lt;/a&gt; last week at plotcon. It was perhaps even more rewarding and fulfilling than &lt;a href=&#34;https://github.com/cpsievert/plotcon17&#34;&gt;my previous plotcon workshop&lt;/a&gt; – I saw more attendees grasping concepts, accomplishing exercises, asking great questions, and most importantly, modifying code examples to analyze their own data. There are a few things I think I improved upon this year which helped contribute to the success, so I thought I would share some ideas that can generalize to other R (or, even more generally, data scienc-y) workshops.&lt;/p&gt;
&lt;div id=&#34;inspire-first-mindful-explanation-later&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Inspire first 😲, mindful explanation later 💁&lt;/h2&gt;
&lt;p&gt;To spark genuine interest and enthusiasm, it’s important to first demonstrate the power of the tools covered in the workshop. For my ‘plotly for R’ workshop, which is more specifically about ‘creating &amp;amp; using interactive graphics for exploratory data analysis (EDA)’, I first focus on the power of &lt;em&gt;using&lt;/em&gt; interactive graphics to &lt;a href=&#34;https://vimeo.com/202650161&#34;&gt;perform&lt;/a&gt; &lt;a href=&#34;https://vimeo.com/239695664&#34;&gt;analysis&lt;/a&gt; &lt;a href=&#34;https://vimeo.com/202647310&#34;&gt;tasks&lt;/a&gt;. In an EDA context though, that power depends on the amount of &lt;a href=&#34;https://talks.cpsievert.me/20170803&#34;&gt;friction involved with &lt;em&gt;creating&lt;/em&gt; graphics&lt;/a&gt;, since during EDA we don’t immediately know which graphics are informative, and likely have to iterate through many uninteresting graphics to find interesting ones.&lt;/p&gt;
&lt;p&gt;With this &lt;a href=&#34;http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.31.1928&#34;&gt;delicate balance&lt;/a&gt; in mind, I like taking a ‘solution first’ approach that focuses first and foremost on the visuals and analysis (i.e., &lt;em&gt;using&lt;/em&gt; interactive graphics), and then move on to explain the programming details (i.e., &lt;em&gt;creating&lt;/em&gt; interactive graphics). I also try to be mindful of what knowledge is required to understand the implementation when ordering the workshop content, so I can introduce programming concepts as I need them, but also have a clear motivation as to &lt;em&gt;why&lt;/em&gt; they’re needed. I also think basing the implementation on &lt;a href=&#34;https://cran.r-project.org/web/packages/tidyr/vignettes/tidy-data.html&#34;&gt;tidy-data principles&lt;/a&gt; is almost always a good idea since you’ll likely be able to reuse those principles and concepts in several different contexts which should help convince your audience that &lt;em&gt;they&lt;/em&gt; can do &lt;a href=&#34;http://varianceexplained.org/r/teach-hard-way/&#34;&gt;powerful things quickly&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;encourage-curiosity-about-data&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Encourage curiosity about data 🤔 📊&lt;/h2&gt;
&lt;p&gt;A big reason why I like this “solution first” approach is that attendees are less likely to get overwhelmed with programming details and more likely to ask interesting data analysis related questions. It also encourages a more natural train of thought for analysts; where questions derive from curiosity about the data, not the software tool. As a result, attendees tend to ask more creative questions that are not necessarily bound to technology restrictions, and thus, I often get questions that I’ve never considered about data that I know quite well! These questions often take the form: “Given that we’ve seen X, I wonder if Y is true? Can plotly do Z [to answer question Y]?”. This leads to a much more fruitful discussion (for everyone!) than if I were just to explain that plotly can do Z.&lt;/p&gt;
&lt;p&gt;Furthermore, by keeping the focus on asking questions about data, attendees are more likely to apply what they’ve learned to their own data. In fact, one attendee said the following:&lt;/p&gt;
&lt;p&gt;“Carson was very good in answering questions about specific use cases related to our own projects..so that always helps when you are able to see that &lt;strong&gt;techniques being presented can be made to work in context of your own datasets.&lt;/strong&gt;”&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;understand-your-audience&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Understand your audience 🕵️‍♀️&lt;/h2&gt;
&lt;p&gt;On a more general level, it seems the reason why this “solution first” approach works so well is because learning a new language is hard, but it can be made easier by building upon existing language or knowledge. So, of course, before preparing workshop materials, I always take some time to understand the audience. I do this by asking attendees to fill out a survey about their background several weeks before the workshop, so I can focus on concepts that I think will be most widely useful.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;encourage-collaboration&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Encourage collaboration 👩‍💻 👨‍💻&lt;/h2&gt;
&lt;p&gt;In addition to asking attendees to fill out a survey several weeks beforehand, I also invite them to a Slack group, mainly for the ease of communication and knowledge sharing during the workshop, but also to encourage interaction before, during, and after the workshop. In fact, my very first &lt;em&gt;your turn exercise&lt;/em&gt;&lt;a href=&#34;#fn1&#34; class=&#34;footnote-ref&#34; id=&#34;fnref1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; requires everyone to send me and their neighbor (via Slack) three things they hope to take away from the workshop. This way I can make sure everyone is on Slack which seems to increase the amount of collaboration among everyone.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;bring-your-work-environment-to-them&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Bring your work environment to them 💼 💻&lt;/h2&gt;
&lt;p&gt;Before the workshop, I also ask attendees to download my &lt;a href=&#34;https://hub.docker.com/r/cpsievert/workshops/&#34;&gt;cpsievert/workshops&lt;/a&gt; Docker image on the machine that they plan on bringing. This way, in theory, we don’t waste any time on setup, and attendees have immediate access to a computational environment with all the materials and software dependencies for following demos and performing exercises. Moreover, since this image builds off of &lt;a href=&#34;https://hub.docker.com/r/rocker/rstudio/&#34;&gt;rocker/rstudio&lt;/a&gt;, they can also easily run RStudio via their web browser which provides a nice and consistent user experience. In practice, I’ve found about 1 in 4 attendees actually try to get Docker setup before the workshop, but with a little time and help, almost everyone can get it working.&lt;/p&gt;
&lt;p&gt;That being said, there are bound to be issues that are difficult to immediately resolve (e.g., not enough disk space on the host machine), so in that case, I provide a USB with the workshop materials, and 🙏 they can install the required software (in theory, if you include a &lt;a href=&#34;http://r-pkgs.had.co.nz/description.html&#34;&gt;DESCRIPTION&lt;/a&gt; file with all your R dependencies for the workshop, they can &lt;code&gt;devtools::install()&lt;/code&gt; R packages, but you’ll still likely run into system dependency issues).&lt;/p&gt;
&lt;p&gt;In the future, I may experiment with hosting workshop containers on the cloud, so that attendees can just visit a web link to follow along, but I’m not sure if the convenience is necessarily worth the cost.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;looking-forward&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Looking forward 🔮&lt;/h2&gt;
&lt;p&gt;I really enjoy running R workshops and hope to continue improving and developing more of them. This is especially true of the ‘plotly for R’ workshop – it’s incredibly fulfilling to have others find your work useful for accomplishing their own work. Longer term though I’d like to spend more time developing other workshops that dive deeper into different aspects of the &lt;a href=&#34;https://www.tidyverse.org/&#34;&gt;tidyverse&lt;/a&gt;, &lt;a href=&#34;http://shiny.rstudio.com/&#34;&gt;shiny&lt;/a&gt;, statistical modeling, and more. In fact, I’ll be attending RStudio’s “train the trainer” workshop (and giving a talk!) during &lt;a href=&#34;https://www.rstudio.com/conference/&#34;&gt;rstudio::conf&lt;/a&gt; this year which I hope will give me more and better ideas for running successful R workshops. Hope to see you there!&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&#34;fn1&#34;&gt;&lt;p&gt;Your turn exercises are largely designed to reinforce important concepts and break up the lecture every 10-20 minutes.&lt;a href=&#34;#fnref1&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>plotly 4.7.1 now on CRAN</title>
      <link>/2017/07/13/plotly-4.7.1-now-on-cran.html</link>
      <pubDate>Thu, 13 Jul 2017 00:00:00 +0000</pubDate>
      
      <guid>/2017/07/13/plotly-4.7.1-now-on-cran.html</guid>
      <description>&lt;p&gt;I&#39;m excited to announce that plotly 4.7.1 is now on CRAN! Along with some important bug fixes and numerous improvements to the underlying plotly.js library, this release includes an exciting new R-specific feature -- the ability to &lt;em&gt;modify&lt;/em&gt; (i.e., update without a full redraw) an existing plotly graph inside a shiny app via the new &lt;code&gt;plotlyProxy()&lt;/code&gt; function. In other words, this proxy interface allows one to perform more efficient and responsive updates to a plotly graph within a shiny app. Before I provide an overview of the proxy interface, lets jump right into some of new plotly.js goodies.&lt;/p&gt;
&lt;div id=&#34;new-plotly.js-goodies&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;New plotly.js goodies&lt;/h2&gt;
&lt;p&gt;Upgrading the R package from 4.7.0 to 4.7.1 upgrades the corresponding plotly.js version from 1.27.1 to 1.29.2. A number of exciting improvements have been added, just to name a few: select/lasso events for scattergl/scattermapbox trace types, 3D annotations, contour labelling, and even touch events on mobile. For quite a while now, R users have been able to &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html&#34;&gt;link multiple views (without shiny)&lt;/a&gt; using nearly any (SVG) trace type (e.g., scatter, bar, heatmap, etc), but the new brush events on scattergl/scattermapbox trace types allow us to brush way more points and trigger selections via a map. Here is an example of highlighting earthquakes west of Fiji to compare the relative frequency of their magnitude and number of reporting stations (to the overall relative frequency):&lt;/p&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;p&gt;&lt;img src=&#34;http://i.imgur.com/l61zu6R.gif&#34; width=900 height=400 /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;And the R code to generate the (self-contained!) HTML:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(crosstalk)
eqs &lt;- SharedData$new(quakes)

# you need a mapbox API key to use plot_mapbox()
# https://www.mapbox.com/signup/?route-to=https://www.mapbox.com/studio/account/tokens/
map &lt;- plot_mapbox(eqs, x = ~long, y = ~lat) %&gt;%
  add_markers(color = ~depth) %&gt;%
  layout(
    mapbox = list(
      zoom = 2,
      center = list(lon = ~mean(long), lat = ~mean(lat))
    )
  ) %&gt;%
  highlight(&#34;plotly_selected&#34;)

# shared properties of the two histograms
hist_base &lt;- plot_ly(eqs, color = I(&#34;black&#34;), histnorm = &#34;probability density&#34;) %&gt;%
  layout(barmode = &#34;overlay&#34;, showlegend = FALSE) %&gt;%
  highlight(selected = attrs_selected(opacity = 0.5))

histograms &lt;- subplot(
  add_histogram(hist_base, x = ~mag),
  add_histogram(hist_base, x = ~stations),
  nrows = 2, titleX = TRUE
)

bscols(histograms, map)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another super cool and easy-to-use plotly.js feature is contour line labelling:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(z = volcano, type = &#34;contour&#34;, contours = list(showlabels = TRUE)) %&gt;%
  colorbar(title = &#34;Elevation \n in meters&#34;)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/21126/.embed&#34; width=&#34;100%&#34; height=&#34;400&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;To learn more about all the new plotly.js improvements, read the plotly.js &lt;a href=&#34;https://github.com/plotly/plotly.js&#34;&gt;release notes&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;modifying-plotly-graphs-via-plotlyproxy&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Modifying plotly graphs via &lt;code&gt;plotlyProxy()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The design of &lt;strong&gt;plotly&lt;/strong&gt;&#39;s new proxy interface is inspired by similar interfaces in &lt;strong&gt;leaflet&lt;/strong&gt; and &lt;strong&gt;DT&lt;/strong&gt; (thanks Joe Cheng and Yihui Xie!). That is, &lt;code&gt;plotlyProxy()&lt;/code&gt; initiates a proxy object just like &lt;code&gt;leafletProxy()&lt;/code&gt;/&lt;code&gt;dataTableProxy()&lt;/code&gt; by referencing a shiny output ID. However, at least for now, you &lt;em&gt;must&lt;/em&gt; use the &lt;code&gt;plotlyProxyInvoke()&lt;/code&gt; function to modify a &lt;code&gt;plotlyProxy()&lt;/code&gt; object, which requires knowledge/use of a &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/&#34;&gt;plotly.js method&lt;/a&gt; for the updating logic (among them, &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlyrestyle&#34;&gt;Plotly.restyle&lt;/a&gt;, &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlyrelayout&#34;&gt;Plotly.relayout&lt;/a&gt;, &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlyaddtraces&#34;&gt;Plotly.addTraces&lt;/a&gt;, and &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlydeletetraces&#34;&gt;Plotly.deleteTraces&lt;/a&gt; are the most widely useful). This simple shiny app uses &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlyrestyle&#34;&gt;Plotly.restyle&lt;/a&gt; to change the fillcolor of Canada (i.e., polygons) in response to the dropdown.&lt;/p&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;p&gt;&lt;img src=&#34;http://i.imgur.com/PzDMqZ0.gif&#34; width=800 height=400 /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Notice how the map and the outline of Canada are not effected (i.e., are not redrawn) when the fill color changes. The code for the app is below. Notice how, instead of having &lt;code&gt;renderPlotly()&lt;/code&gt; regenerate the map in response to a change in &lt;code&gt;input$color&lt;/code&gt; (i.e., the &#34;old&#34; or &#34;naive&#34; way of updating a plotly graph which always uses &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlynewplot&#34;&gt;Plotly.newPlot&lt;/a&gt;), it uses &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlyrestyle&#34;&gt;Plotly.restyle&lt;/a&gt; via &lt;code&gt;plotlyProxyInvoke()&lt;/code&gt; to perform a more efficient update.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# you can also run this example via the new plotly_example() function!
# plotly_example(&#34;shiny&#34;, &#34;proxy_restyle_canada&#34;)

library(shiny)
library(plotly)

ui &lt;- fluidPage(
  selectInput(&#34;color&#34;, &#34;Canada&#39;s fillcolor&#34;, colors(), selected = &#34;black&#34;),
  plotlyOutput(&#34;map&#34;)
)

server &lt;- function(input, output, session) {
  
  output$map &lt;- renderPlotly({
    map_data(&#34;world&#34;, &#34;canada&#34;) %&gt;%
      group_by(group) %&gt;%
      plot_mapbox(x = ~long, y = ~lat, color = I(&#34;black&#34;)) %&gt;%
      add_polygons() %&gt;%
      layout(
        mapbox = list(center = list(lat = ~median(lat), lon = ~median(long)))
      )
  })
  
  observeEvent(input$color, {
    plotlyProxy(&#34;map&#34;, session) %&gt;%
      plotlyProxyInvoke(&#34;restyle&#34;, list(fillcolor = toRGB(input$color)))
  })
  
}

shinyApp(ui, server)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s worth noting that using &lt;code&gt;plotlyProxyInvoke()&lt;/code&gt; requires knowledge of the &lt;a href=&#34;https://plot.ly/r/reference/&#34;&gt;figure reference&lt;/a&gt; and the &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/&#34;&gt;plotly.js API&lt;/a&gt;. Thus, it can help to have some knowledge of how your plots are actually represented in JSON, which you can always obtain via &lt;code&gt;plotly_json()&lt;/code&gt;, for example:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p &lt;- plot_ly(economics, x = ~pce, y = ~psavert, z = ~unemploy, color = ~as.numeric(date), mode = &#34;markers+lines&#34;)
plotly_json(p)&lt;/code&gt;&lt;/pre&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;p&gt;&lt;img src=&#34;http://i.imgur.com/7VQUsxC.gif&#34; width=800 height=400 /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;This gives us a glimpse into what the R package actually sends along to the &lt;a href=&#34;https://plot.ly/javascript/plotlyjs-function-reference/#plotlyplot&#34;&gt;newPlot method&lt;/a&gt; to generate the initial view on page load. In this case, the R package generates scatter3d &lt;a href=&#34;https://plot.ly/r/reference/#scatter3d-marker&#34;&gt;marker&lt;/a&gt; and &lt;a href=&#34;https://plot.ly/r/reference/#scatter3d-line&#34;&gt;line&lt;/a&gt; objects. We could use a similar &lt;code&gt;plotlyProxyInvoke()&lt;/code&gt; pattern as before to alter the value of certain attribute(s) of these objects (e.g., marker/line size/width):&lt;/p&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;p&gt;&lt;img src=&#34;http://i.imgur.com/jXLW2fz.gif&#34; width=800 height=400 /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# you can also run this example via the new plotly_example() function!
# plotly_example(&#34;shiny&#34;, &#34;proxy_restyle_economics&#34;)

library(shiny)
library(plotly)

ui &lt;- fluidPage(
  sliderInput(&#34;marker&#34;, &#34;Marker size&#34;, min = 0, max = 20, value = 8),
  sliderInput(&#34;path&#34;, &#34;Path size&#34;, min = 0, max = 30, value = 2),
  plotlyOutput(&#34;p&#34;)
)

server &lt;- function(input, output, session) {
  
  output$p &lt;- renderPlotly({
    plot_ly(
      economics, x = ~pce, y = ~psavert, z = ~unemploy, 
      color = ~as.numeric(date), mode = &#34;markers+lines&#34;
    )
  })
  
  observeEvent(input$marker, {
    plotlyProxy(&#34;p&#34;, session) %&gt;%
      plotlyProxyInvoke(
        &#34;restyle&#34;, 
        # could also do list(marker = list(size = input$marker))
        # but that overwrites the existing marker definition
        # https://github.com/plotly/plotly.js/issues/1866#issuecomment-314115744
        list(marker.size = input$marker)
      )
  })
  
  observeEvent(input$path, {
    plotlyProxy(&#34;p&#34;, session) %&gt;%
      plotlyProxyInvoke(
        &#34;restyle&#34;, list(line.width = input$path)
      )
  })
  
}

shinyApp(ui, server)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you might be wondering something along these lines of: &#34;how on earth am I supposed to know/remember what attributes a scatter3d line object has?&#34; One option is to search through the figure reference, but I prefer to use the &lt;code&gt;schema()&lt;/code&gt; function since it allows me to more easily traverse the reference and get more information about acceptable/default attribute values. For example, when creating this app, I forgot what line attribute controlled its size/width, so I did the following:&lt;/p&gt;
&lt;div align=&#34;center&#34;&gt;
&lt;p&gt;&lt;img src=&#34;http://i.imgur.com/vk4FxLI.gif&#34; width=800 height=400 /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;I hope you find this new release useful and this post informative for creating more performant shiny apps! If you&#39;re interested in seeing more examples of &lt;code&gt;plotlyProxy()&lt;/code&gt; in action, see &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/inst/examples/shiny/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Developing tools for exploratory visualization</title>
      <link>/2017/06/13/developing-tools-for-exploratory-visualization.html</link>
      <pubDate>Tue, 13 Jun 2017 00:00:00 +0000</pubDate>
      
      <guid>/2017/06/13/developing-tools-for-exploratory-visualization.html</guid>
      <description>&lt;p&gt;I find it incredibly fulfilling to work on projects that &lt;a href=&#34;https://www.youtube.com/watch?v=zMLVjnRZ3dQ&amp;amp;feature=youtu.be&amp;amp;t=10m41s&#34;&gt;enhance the productivity&lt;/a&gt; of other data scientists. After all, most data scientists need to &lt;em&gt;maximize&lt;/em&gt; time spent formulating, examining, and refining questions about data; and &lt;em&gt;minimize&lt;/em&gt; time translating those thoughts into machine code. I’ve &lt;a href=&#34;https://cpsievert.github.io/talks/&#34;&gt;talked&lt;/a&gt; at &lt;a href=&#34;http://cpsievert.github.io/talks/20161212a/&#34;&gt;great&lt;/a&gt; &lt;a href=&#34;http://cpsievert.github.io/talks/20161212b/&#34;&gt;lengths&lt;/a&gt; about how &lt;a href=&#34;https://cpsievert.github.io/plotcon17/talk&#34;&gt;my work on plotly&lt;/a&gt; fits into this context, which roughly speaking, allows one to leverage many benefits of interactive web graphics &lt;em&gt;without any knowledge of web technologies&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.nytimes.com/interactive/2014/upshot/mapping-the-spread-of-drought-across-the-us.html&#34;&gt;If&lt;/a&gt; &lt;a href=&#34;https://www.nytimes.com/interactive/2014/04/24/upshot/facebook-baseball-map.html&#34;&gt;you&lt;/a&gt; &lt;a href=&#34;https://www.nytimes.com/interactive/2014/upshot/buy-rent-calculator.html&#34;&gt;keep&lt;/a&gt; &lt;a href=&#34;https://www.nytimes.com/2014/04/23/upshot/the-american-middle-class-is-no-longer-the-worlds-richest.html&#34;&gt;up&lt;/a&gt; &lt;a href=&#34;https://www.nytimes.com/interactive/2014/07/08/upshot/how-the-year-you-were-born-influences-your-politics.html&#34;&gt;with&lt;/a&gt; &lt;a href=&#34;https://www.nytimes.com/interactive/2014/06/05/upshot/how-the-recession-reshaped-the-economy-in-255-charts.html&#34;&gt;online&lt;/a&gt; &lt;a href=&#34;https://www.nytimes.com/interactive/2014/11/04/upshot/senate-maps.html&#34;&gt;media&lt;/a&gt;, the benefits of interactive web graphics are pretty clear: they can help grab the audience’s attention, enchance knowledge transfer, and allow the audience to further investigate detailed information. And yes, assuming you’re a web developer, we already have &lt;a href=&#34;https://d3js.org/&#34;&gt;awesome&lt;/a&gt; &lt;a href=&#34;https://github.com/plotly/plotly.js/&#34;&gt;tools&lt;/a&gt; for creating web-based data visualizations; but even if you’re a &lt;a href=&#34;https://www.slideshare.net/ryanorban/bridging-the-gap-between-data-science-engineer-building-highperformance-teams/5?src=clipshare&#34;&gt;polyglot data science unicorn&lt;/a&gt;, you still shouldn’t be writing JavaScript/JSON to do exploratory analysis (where the most useful view/question of the data is not yet known). That’s because &lt;a href=&#34;http://r4ds.had.co.nz/explore-intro.html&#34;&gt;data exploration requires non-linear iteration between data transformation/modeling/visualization&lt;/a&gt; (which a web browser was not designed to do). That being said, &lt;a href=&#34;https://plotcon17.cpsievert.me/talk/#9&#34;&gt;interactive graphics are certainly useful for exploration&lt;/a&gt;,&lt;a href=&#34;#fn1&#34; class=&#34;footnote-ref&#34; id=&#34;fnref1&#34;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; which is partially why we’ve seen a recent explosion in R/Python/Julia interfaces to JavaScript graphing libraries.&lt;/p&gt;
&lt;p&gt;I feel very fortunate to have maintained the (completely free and open source) &lt;a href=&#34;https://plotly-book.cpsievert.me/&#34;&gt;R interface&lt;/a&gt; to &lt;a href=&#34;https://github.com/plotly/plotly.js&#34;&gt;plotly.js&lt;/a&gt; for over 2 years now. I also feel very fortunate to be in a position where the plotly.js maintainers respond very well to my &lt;a href=&#34;https://github.com/plotly/plotly.js/issues?utf8=%E2%9C%93&amp;amp;q=is%3Aissue%20author%3Acpsievert%20&#34;&gt;bug reports and feature requests&lt;/a&gt;.&lt;a href=&#34;#fn2&#34; class=&#34;footnote-ref&#34; id=&#34;fnref2&#34;&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; Now that I’ve &lt;a href=&#34;./cv.pdf&#34;&gt;graduated&lt;/a&gt; and had some time to reflect on the past few years, I’ve been thinking a bit more generally about data science software development, and how I can keep sustaining this type of work through my &lt;a href=&#34;./consulting&#34;&gt;consulting&lt;/a&gt; services.&lt;/p&gt;
&lt;p&gt;Generally speaking, designing data science software requires making hard decisions about which abstractions to make, and perhaps more importantly, which abstractions &lt;em&gt;not&lt;/em&gt; to make (especially with respect to visualization). Doing this well requires an intimate knowledge of the most common/frustating/difficult tasks within the given domain, which means data science software developers should:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Be familiar with the vast ecosystem of existing tools or else we risk re-inventing the wheel.&lt;a href=&#34;#fn3&#34; class=&#34;footnote-ref&#34; id=&#34;fnref3&#34;&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Get our hands dirty analyzing data, and applying our tools to real data-driven problems, or else we risk working on insignificant problems.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is why I spend a good chunk of my time researching the constantly expanding ecosystem of R packages and using some of those tools to do real data analysis. Doing so not only forces you to &lt;a href=&#34;https://en.wikipedia.org/wiki/Eating_your_own_dog_food&#34;&gt;eat your own dog food&lt;/a&gt;, but helps you focus on the bigger picture, rather than drowning in a sea of issues that don’t effect most users. For example, most of the &lt;a href=&#34;https://plotly-book.cpsievert.me/linking-views-without-shiny.html&#34;&gt;new linking framework in plotly&lt;/a&gt; was motivated and (indirectly) supported by work on &lt;a href=&#34;./software/#eechidna&#34;&gt;eechidna&lt;/a&gt;/&lt;a href=&#34;./software/#pedestrians&#34;&gt;pedestrians&lt;/a&gt;/&lt;a href=&#34;./software/#bcviz&#34;&gt;bcviz&lt;/a&gt;. I hope to continue doing this sort of work with the help of more &lt;a href=&#34;./consulting&#34;&gt;clients&lt;/a&gt; that have interesting data-driven problems and need better ways to explore/present their data visually.&lt;/p&gt;
&lt;p&gt;Another thing I’ve learned through this work is that even the best programming interfaces do about 80% of what you’d like them to do. That number is even smaller for general-purpose visualization software (e.g., plotly) since their scope is so impossibly large. Fortunately, working with open-source tools means that we are (usually) free to modify the software to fit a particular use case. That sounds great in theory, but in practice, it can be a time-consuming and ultimately futile effort without an intimate understanding of the software. Since I have an intimate understanding of plotly and many other R packages, I also offer my &lt;a href=&#34;./consulting&#34;&gt;clients&lt;/a&gt; the ability to adapt/modify/fix existing open-source tools for a particular project.&lt;/p&gt;
&lt;!--
As someone with a [formal training in statistics](/cv.pdf) who picked up computing/programming relatively informally, I know all too well how easy it is for [statistical thinking to be swamped by unessential &amp; tedious programming tasks](https://plotcon17.cpsievert.me/talk/#5). 

Moreover, expecting data scientists to be polyglot programmers can be harmful: it steals away cognitive effort that could be better spent learning new mathematics/statistical methods, gaining domain expertise, and also contributes to [this unicorn mentality](http://www.rwjf.org/en/library/infographics/infographic-the-myth-of-the-data-scientist-unicorn.html) that the field suffers from. However, the fact remains, if data scientists want to effectively *do* data analysis and *communicate* their results, they need to juggle a myriad of technologies (R, Python, JavaScript, HTML, SVG, etc).

This is especially true if you need to *do* data analysis, then *present* your results to others in a dynamic/interactive web-based format. That is, shifting from the exploratory phase of an analysis to the communication phase can involve an expensive context shift between tools (e.g. R/Python for exploration, JavaScript/D3 for visualization). Moreover, most web-based tools simply weren&#39;t designed for fast iteration time *between* common data visualizations, which is a critical


I run into these scenarios quite frequently with other people&#39;s software, but admittedly, probably even more so with my own software. As a result, I&#39;ve built confidence in my ability to rapidly prototype interactive data visualizations, and customize them to fit a particular use case if an existing solution doesn&#39;t already exist.

  I feel very fortunate to have spent numerous years of my statistics PhD in this domain learing from mentors that have been this sort of work for 30+ years. They helped me not to forget the importance of 1 and 2
  
  instilled in me how important it is to not become hyper-focused on software engineering problems
  --&gt;
&lt;div class=&#34;footnotes&#34;&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id=&#34;fn1&#34;&gt;&lt;p&gt;Assuming that the time spent iterating from one visualization to the next is relatively small.&lt;a href=&#34;#fnref1&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn2&#34;&gt;&lt;p&gt;Having tracked development on similar R packages, like &lt;a href=&#34;https://github.com/rstudio/ggvis&#34;&gt;ggvis&lt;/a&gt;, I’m convinced that a strong relationship amongst development teams (i.e., R and JavaScript devs) is necessary to maintain such a project.&lt;a href=&#34;#fnref2&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id=&#34;fn3&#34;&gt;&lt;p&gt;That isn’t to say that “re-inventing the wheel” can’t be a good thing, especially when it leads to a better wheel. In my opinion, especially in academia, there is too much of a focus on whether tool(s) &lt;em&gt;exist&lt;/em&gt;, and not nearly enough attention is paid to whether they are &lt;em&gt;usable&lt;/em&gt;.&lt;a href=&#34;#fnref3&#34; class=&#34;footnote-back&#34;&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>plotly 4.7.0 now on CRAN</title>
      <link>/2017/05/30/plotly-4.7.0-now-on-cran.html</link>
      <pubDate>Tue, 30 May 2017 00:00:00 +0000</pubDate>
      
      <guid>/2017/05/30/plotly-4.7.0-now-on-cran.html</guid>
      <description>I’m super excited about plotly 4.7.0 – it includes numerous improvements and new features related to performance, mapping, and API requests. It also includes support for something &lt;a href=&#34;https://twitter.com/hadleywickham/status/709025365558054912&#34;&gt;folks have wanted for a very long time&lt;/a&gt; – fixed coordinates via &lt;code&gt;ggplotly()&lt;/code&gt;! In other words, if you use &lt;code&gt;coord_equal()&lt;/code&gt;, &lt;code&gt;coord_fixed()&lt;/code&gt;, etc to specify a ratio between the visual represntation of data units on positional axes (a key property of maps) in &lt;strong&gt;ggplot2&lt;/strong&gt;, it should just work&lt;sup&gt;TM&lt;/sup&gt; when converted via &lt;code&gt;ggplotly()&lt;/code&gt;! It also has support for the stellar new &lt;code&gt;geom_sf()&lt;/code&gt; – an official &lt;strong&gt;ggplot2&lt;/strong&gt; geom that is so new, it is currently only available through the development version of &lt;strong&gt;ggplot2&lt;/strong&gt;. For this and other reasons, I recommend using the development version of &lt;strong&gt;ggplot2&lt;/strong&gt; if you can:
&lt;pre&gt;&lt;code&gt;devtools::install_github(&#34;tidyverse/ggplot2&#34;)
install.packages(&#34;plotly&#34;)&lt;/code&gt;&lt;/pre&gt;
At plotcon Oakland, I held a &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/&#34;&gt;workshop&lt;/a&gt; where I touched on why the new &lt;strong&gt;sf&lt;/strong&gt; package and &lt;code&gt;geom_sf()&lt;/code&gt; are so awesome for mapping in R, and &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/day1/#14&#34;&gt;how to make these maps interactive via &lt;code&gt;ggplotly()&lt;/code&gt;&lt;/a&gt;. There are lots of other goodies in those workshop slides, such as &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/day1/#43&#34;&gt;embedding raster images&lt;/a&gt;, converting &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/day1/#44&#34;&gt;&lt;strong&gt;ggmap&lt;/strong&gt; plots&lt;/a&gt;, an overview of &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/day2/#4&#34;&gt;animation&lt;/a&gt;, &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/day2/#15&#34;&gt;highlighting&lt;/a&gt;, and &lt;a href=&#34;https://cpsievert.github.io/plotcon17/workshop/day2/#39&#34;&gt;filtering&lt;/a&gt;. Also, some of the “your turn” exercises show you how to combine these concepts to do neat stuff like &lt;a href=&#34;https://gist.github.com/cpsievert/eca3ff3eba67ab6b4719c748dafd5c4a&#34;&gt;outline geo-spatial polygons on hover&lt;/a&gt; or &lt;a href=&#34;https://gist.github.com/cpsievert/fa56bd89122e395803f30602b774dbe1&#34;&gt;annotate geo-spatial polygons on click&lt;/a&gt;:

&lt;div align=&#34;center&#34; &gt;
  &lt;img src=&#34;http://i.imgur.com/3m3dNgP.gif&#34; width=&#34;600&#34; height=&#34;342&#34; /&gt;
&lt;/div&gt;

Updating to 4.7.0 may also yield big speed improvements at print time, especially when plotting a large number of lines, paths, or polygons in a single trace. For a bit of context, this fairly simple example with 46 lines now takes a third of the time to print (about 1 instead of 3 seconds).
&lt;pre&gt;&lt;code&gt;plot_ly(txhousing) %&gt;%
  group_by(city) %&gt;%
  add_lines(x = ~date, y = ~median)&lt;/code&gt;&lt;/pre&gt;
The speed-up is a direct result of making (the previously internal, but now exported) function &lt;code&gt;group2NA()&lt;/code&gt; much more efficient (huge thanks to Matt Summersgill for the help here). This function is used on any ggplot2 geom which can be reduced to a path or a polygon, so the impact should be large and widespread! This improvement was made possible through the new &lt;strong&gt;data.table&lt;/strong&gt; dependency, which I hope to leverage more down the road to make other plots faster to print.

This release also updates the plotly.js version from 1.26.1 to 1.27.1, so you can leverage the latest plotly.js features, such as &lt;a href=&#34;https://plot.ly/r/parallel-coordinates-plot/&#34;&gt;parallel coordinates&lt;/a&gt; and &lt;a href=&#34;https://gist.github.com/cpsievert/08a21b22904b96a6a2b5e7cf24d4fdd0&#34;&gt;Sankey diagrams&lt;/a&gt;. Numerous other improvements and bug fixes (especially for &lt;code&gt;api_create()&lt;/code&gt;) are coming with this release, please see the &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md&#34;&gt;NEWS&lt;/a&gt; file for more info.

Happy plotting!</description>
    </item>
    
    <item>
      <title>plotly 4.6.0 now on CRAN</title>
      <link>/2017/04/25/plotly-4.6.0-now-on-cran.html</link>
      <pubDate>Tue, 25 Apr 2017 00:00:00 +0000</pubDate>
      
      <guid>/2017/04/25/plotly-4.6.0-now-on-cran.html</guid>
      <description>I&#39;m super excited to announce that plotly 4.6.0 is now on CRAN! Go ahead and install it with:
&lt;code&gt;
install.packages(&#34;plotly&#34;)
&lt;/code&gt;

This release brings a ton of new features and improvements -- some of which are over in the year making. I recently held a webinar introducing the biggest features, including &lt;a href=&#34;https://cpsievert.github.io/plotly_book/linking-views-without-shiny.html&#34;&gt;linked views&lt;/a&gt;, &lt;a href=&#34;https://cpsievert.github.io/plotly_book/key-frame-animations.html&#34;&gt;animation&lt;/a&gt;, and &lt;a href=&#34;https://rstudio.github.io/crosstalk/&#34;&gt;crosstalk&lt;/a&gt; integration. In addition to the webinar &lt;a href=&#34;https://vimeo.com/214301880&#34;&gt;recording&lt;/a&gt;, some good resources for getting up-to-speed include new demos (`demo(package = &#34;plotly&#34;)`), help pages (`help(highlight)` and `help(animation)`), and the official &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md&#34;&gt;NEWS&lt;/a&gt; file. I also recommend checking out my &lt;a href=&#34;https://vimeo.com/cpsievert&#34;&gt;vimeo page&lt;/a&gt; for some more advanced applications of the linked views framework.

My upcoming &lt;a href=&#34;https://plotcon.plot.ly/workshops&#34;&gt;plotcon workshop&lt;/a&gt; will be a great opportunity to learn all these new features over 2 full days of lectures, demos, hands-on exercises, and one-on-one Q&amp;amp;A.

PS. I can&#39;t wait to see what you do with these new features! And I always love hearing from the community; so &lt;a href=&#34;https://twitter.com/cpsievert&#34;&gt;tweet me&lt;/a&gt; if you run into issues/questions, want to share your work, and/or just want to say hi! :)</description>
    </item>
    
    <item>
      <title>News and Updates Surrounding plotly for R</title>
      <link>/2017/04/12/news-and-updates-surrounding-plotly-for-r.html</link>
      <pubDate>Wed, 12 Apr 2017 00:00:00 +0000</pubDate>
      
      <guid>/2017/04/12/news-and-updates-surrounding-plotly-for-r.html</guid>
      <description>Today I held a free webinar to announce/present some new exciting features coming with plotly 4.6.0, including animations and multiple linked views. Here is a video of it:

&lt;iframe src=&#34;https://player.vimeo.com/video/214301880&#34; width=&#34;640&#34; height=&#34;480&#34; frameborder=&#34;0&#34; webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;Also, here is a link to the slides used during the presentation:&lt;/p&gt;

&lt;blockquote class=&#34;twitter-tweet&#34; data-lang=&#34;en&#34;&gt;&lt;p lang=&#34;en&#34; dir=&#34;ltr&#34;&gt;Slides from my webinar today  --&lt;a href=&#34;https://t.co/ZMJpaQfpfZ&#34;&gt;https://t.co/ZMJpaQfpfZ&lt;/a&gt;&lt;br&gt;Click on the image here to watch the video (skip to 3min) -- &lt;a href=&#34;https://t.co/brdSPsntGw&#34;&gt;https://t.co/brdSPsntGw&lt;/a&gt;&lt;/p&gt;&amp;mdash; Carson Sievert (@cpsievert) &lt;a href=&#34;https://twitter.com/cpsievert/status/852196070557929472?ref_src=twsrc%5Etfw&#34;&gt;April 12, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src=&#34;https://platform.twitter.com/widgets.js&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
</description>
    </item>
    
    <item>
      <title>Not Found</title>
      <link>/404/</link>
      <pubDate>Tue, 31 Jan 2017 00:00:00 +0000</pubDate>
      
      <guid>/404/</guid>
      <description>&lt;p&gt;Page not found. Please &lt;a href=&#34;mailto:cpsievert1@gmail.com&#34;&gt;notify me&lt;/a&gt; if a page should really exist here or go back to the &lt;a href=&#34;./&#34;&gt;home page&lt;/a&gt;.&lt;/p&gt;

&lt;div align=&#34;center&#34;&gt;
  &lt;img src=&#34;https://www.viralviralvideos.com/wp-content/uploads/meme/2014/06/GIF-Lost-cat.gif&#34; width=&#34;400&#34; height=&#34;200&#34;/&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Upgrading to plotly 4.0 (and above)</title>
      <link>/2016/09/26/upgrading-to-plotly-4.0-and-above.html</link>
      <pubDate>Mon, 26 Sep 2016 00:00:00 +0000</pubDate>
      
      <guid>/2016/09/26/upgrading-to-plotly-4.0-and-above.html</guid>
      <description>&lt;p&gt;I’m excited to announce that plotly’s R package just sent its first CRAN update in nearly four months. To install the update, run &lt;code&gt;install.packages(&#34;plotly&#34;)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This update has breaking changes, enables new features, fixes numerous bugs, and takes us from version 3.6.0 to 4.5.2. To see all the changes, I encourage you to read the &lt;a href=&#34;https://github.com/ropensci/plotly/blob/master/NEWS.md&#34;&gt;NEWS file&lt;/a&gt;. In this post, I’ll highlight the most important changes, explain why they needed to happen, and provide some tips for fixing errors brought about by this update. As you’ll see, this update is mostly about improving the &lt;code&gt;plot_ly()&lt;/code&gt; interface, so &lt;code&gt;ggplotly()&lt;/code&gt; users won’t notice much (if any) change. I’ve also started a &lt;a href=&#34;https://cpsievert.github.io/plotly_book/&#34;&gt;plotly for R book&lt;/a&gt; which provides more narrative than the documentation on &lt;a href=&#34;https://plot.ly/r&#34; class=&#34;uri&#34;&gt;https://plot.ly/r&lt;/a&gt; (which is now updated to 4.0), more recent examples, and features exclusive to the R package. The first three chapters are nearly finished and replace the package vignettes. The later chapters are still in their beginning stages – they discuss features that are still under development, but I plan adding stability, and more documentation in the coming months.&lt;/p&gt;
&lt;div id=&#34;formula-mappings&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Formula mappings&lt;/h2&gt;
&lt;p&gt;In the past, you could use an &lt;em&gt;expression&lt;/em&gt; to reference variable(s) in a data frame, but this no longer works. Consequently, you might see an error like this when you update:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(plotly)
plot_ly(mtcars, x = mpg, y = sqrt(wt))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## Error in plot_ly(mtcars, x = mpg, y = sqrt(wt)): object &#39;wt&#39; not found&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;plot_ly()&lt;/code&gt; now requires a &lt;em&gt;formula&lt;/em&gt; (which is basically an expression, but with a &lt;code&gt;~&lt;/code&gt; prefixed) when referencing variables. You do not &lt;em&gt;have to&lt;/em&gt; use a formula to reference objects that exist in the namespace, but I recommend it, since it helps populate sensible axis/guide title defaults (e.g., compare the output of &lt;code&gt;plot_ly(z = volcano)&lt;/code&gt; with &lt;code&gt;plot_ly(z = ~volcano)&lt;/code&gt; ).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(mtcars, x = ~mpg, y = ~sqrt(wt))&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14541.embed&#34; width=&#34;600&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;There are a number of technical reasons why imposing this change from expressions to formulas is a good idea. If you’re interested in the details, I recommend reading &lt;a href=&#34;https://rpubs.com/hadley/lazyeval&#34;&gt;Hadley Wickham’s notes&lt;/a&gt; on non-standard evaluation, but here’s the gist of the situation:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;Since formulas capture the environment in which they are created, we can be confident that evaluation rules are always correct, no matter the context.&lt;/li&gt;
&lt;li&gt;Compared to expressions/symbols, formulas are easier to program with, which makes writing custom functions around &lt;code&gt;plot_ly()&lt;/code&gt; easier.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;myPlot &lt;- function(x, y, ...) {
  plot_ly(mtcars, x = x, y = y, color = ~factor(cyl), ...)
}
myPlot(~mpg, ~disp, colors = &#34;Dark2&#34;)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14543.embed&#34; width=&#34;600&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Also, it’s fairly easy to convert a string to a formula (e.g., &lt;code&gt;as.formula(&#34;~sqrt(wt)&#34;)&lt;/code&gt;). This trick can be quite useful when programming in shiny (and a variable mapping depends on an input value).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;smarter-defaults&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Smarter defaults&lt;/h2&gt;
&lt;p&gt;Instead of always defaulting to a “scatter” trace, &lt;code&gt;plot_ly()&lt;/code&gt; now infers a sensible trace type (and other attribute defaults) based on the information provided. These defaults are determined by inspecting the vector type (e.g., numeric/character/factor/etc) of positional attributes (e.g., x/y). For example, if we supply a discrete variable to x (or y), we get a vertical (or horizontal) bar chart:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;subplot(
  plot_ly(diamonds, y = ~cut, color = ~clarity),
  plot_ly(diamonds, x = ~cut, color = ~clarity),
  margin = 0.07
) %&gt;% hide_legend() &lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14545.embed&#34; width=&#34;900&#34; height=&#34;500&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Or, if we supply two discrete variables to both x and y:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plot_ly(diamonds, x = ~cut, y = ~clarity)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14547.embed&#34; width=&#34;800&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Also, the order of categories on a discrete axis, by default, is now either alphabetical (for character strings) or matches the ordering of factor levels. This makes it easier to sort categories according to something meaningful, rather than the order in which the categories appear (the old default). If you prefer the old default, use &lt;code&gt;layout(categoryorder = &#34;trace&#34;)&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(dplyr)
# order the clarity levels by their median price
d &lt;- diamonds %&gt;%
  group_by(clarity) %&gt;%
  summarise(m = median(price)) %&gt;%
  arrange(m)
diamonds$clarity &lt;- factor(diamonds$clarity, levels = d[[&#34;clarity&#34;]])
plot_ly(diamonds, x = ~price, y = ~clarity, type = &#34;box&#34;)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14549.embed&#34; width=&#34;800&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;div id=&#34;plot_ly-now-initializes-a-plot&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;&lt;code&gt;plot_ly()&lt;/code&gt; now &lt;em&gt;initializes&lt;/em&gt; a plot&lt;/h2&gt;
&lt;p&gt;Previously &lt;code&gt;plot_ly()&lt;/code&gt; &lt;em&gt;always&lt;/em&gt; produced at least one trace, even when using &lt;code&gt;add_trace()&lt;/code&gt; to add on more traces (if you’re familiar with ggplot2 lingo, a trace is similar to a layer). From now on, you’ll have to specify the &lt;code&gt;type&lt;/code&gt; in &lt;code&gt;plot_ly()&lt;/code&gt; if you want it to always produce a trace:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;subplot(
  plot_ly(economics, x = ~date, y = ~psavert, type = &#34;scatter&#34;) %&gt;% 
    add_trace(y = ~uempmed) %&gt;%
    layout(yaxis = list(title = &#34;Two Traces&#34;)),
  plot_ly(economics, x = ~date, y = ~psavert) %&gt;% 
    add_trace(y = ~uempmed) %&gt;% 
    layout(yaxis = list(title = &#34;One Trace&#34;)),
  titleY = TRUE, shareX = TRUE, nrows = 2
) %&gt;% hide_legend()&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14551.embed&#34; width=&#34;800&#34; height=&#34;600&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;Why enforce this change? Often times, when composing a plot with multiple traces, you have attributes that are shared across traces (i.e., global) and attributes that are not. By allowing &lt;code&gt;plot_ly()&lt;/code&gt; to simply initialize the plot and define global attributes, it makes for a much more natural to describe such a plot. Consider the next example, where we declare x/y (longitude/latitude) attributes and alpha transparency globally, but alter trace specific attributes in &lt;code&gt;add_trace()&lt;/code&gt;-like functions. This example also takes advantage of a few other new features:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;The &lt;code&gt;group_by()&lt;/code&gt; function which defines “groups” within a trace (described in more detail in the next section).&lt;/li&gt;
&lt;li&gt;New &lt;code&gt;add_*()&lt;/code&gt; functions which behave like &lt;code&gt;add_trace()&lt;/code&gt;, but are higher-level since they assume a trace type, might set some attribute values (e.g., &lt;code&gt;add_marker()&lt;/code&gt; set the scatter trace mode to marker), and might trigger other data processing (e.g., &lt;code&gt;add_lines()&lt;/code&gt; is essentially the same as &lt;code&gt;add_paths()&lt;/code&gt;, but guarantees values are sorted along the x-axis).&lt;/li&gt;
&lt;li&gt;Scaling is avoided for “AsIs” values (i.e., values wrapped with &lt;code&gt;I()&lt;/code&gt;) which makes it easier directly specify a constant value for a visual attribute(s) (as opposed to mapping data values to visuals).&lt;/li&gt;
&lt;li&gt;More support for R’s graphical parameters such as &lt;code&gt;pch&lt;/code&gt; for symbols and &lt;code&gt;lty&lt;/code&gt; for linetypes.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;map_data(&#34;world&#34;, &#34;canada&#34;) %&gt;%
  group_by(group) %&gt;%
  plot_ly(x = ~long, y = ~lat, alpha = 0.1) %&gt;%
  add_polygons(color = I(&#34;black&#34;), hoverinfo = &#34;none&#34;) %&gt;%
  add_markers(color = I(&#34;red&#34;), symbol = I(17),
              text = ~paste(name, &#34;&lt;br /&gt;&#34;, pop),
              hoverinfo = &#34;text&#34;, data = maps::canada.cities) %&gt;%
  hide_legend()&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14553.embed&#34; width=&#34;800&#34; height=&#34;350&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;div id=&#34;new-interpretation-of-group&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;New interpretation of group&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;group&lt;/code&gt; argument in &lt;code&gt;plot_ly()&lt;/code&gt; has been removed in favor of the &lt;code&gt;group_by()&lt;/code&gt; function. In the past, the &lt;code&gt;group&lt;/code&gt; argument &lt;a href=&#34;https://github.com/ropensci/plotly/issues/381&#34;&gt;incorrectly&lt;/a&gt; &lt;a href=&#34;https://github.com/ropensci/plotly/issues/381&#34;&gt;created&lt;/a&gt; multiple traces. If you want that same behavior, use the new &lt;code&gt;split&lt;/code&gt; argument, but groups are now used to define “gaps” &lt;em&gt;within&lt;/em&gt; a trace. This is more consistent with how ggplot2’s &lt;code&gt;group&lt;/code&gt; aesthetic is translated in &lt;code&gt;ggplotly()&lt;/code&gt;, and is much more efficient than plotting a trace for each group.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;txhousing %&gt;%
  group_by(city) %&gt;%
  plot_ly(x = ~date, y = ~median) %&gt;%
  add_lines(alpha = 0.3)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14555.embed&#34; width=&#34;800&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;The default &lt;a href=&#34;http://plot.ly/r/reference/#layout-hovermode&#34;&gt;hovermode&lt;/a&gt; (compare data on hover) isn’t super useful here since we have only 1 trace to compare, so you may want to add &lt;code&gt;layout(hovermode = &#34;closest&#34;)&lt;/code&gt; when using &lt;code&gt;group_by()&lt;/code&gt;. If you’re group sizes aren’t that large, you may want to use &lt;code&gt;split&lt;/code&gt; to generate one trace per group, then set a constant color (using the &lt;code&gt;I()&lt;/code&gt; function to avoid scaling).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;txhousing %&gt;%
  plot_ly(x = ~date, y = ~median) %&gt;%
  add_lines(split = ~city, color = I(&#34;steelblue&#34;), alpha = 0.3)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14557.embed&#34; width=&#34;800&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;In the coming months, we will have better ways to identify/highlight groups to help combat overplotting (see &lt;a href=&#34;http://rpubs.com/cpsievert/212318&#34;&gt;here&lt;/a&gt; for example). This same interface can be used to coordinate multiple linked plots, which is a powerful tool for exploring multivariate data and presenting multivariate results (see &lt;a href=&#34;http://rpubs.com/cpsievert/206872&#34;&gt;here&lt;/a&gt; and &lt;a href=&#34;http://rpubs.com/cpsievert/204407&#34;&gt;here&lt;/a&gt; for examples).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;new-plotly-object-representation&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;New plotly object representation&lt;/h2&gt;
&lt;p&gt;Prior to version 4.0, plotly functions returned a data frame with special attributes attached (needed to track the plot’s attributes). At the time, I thought this was the right way to enable a “data-plot-pipeline” where a plot is described as a sequence of visual mappings and data manipulations. For a number of reasons, I’ve been convinced otherwise, and decided the central plotly object should inherit from an htmlwidget object instead. This change does not destroy our ability to implement a “data-plot-pipeline”, but it does, in a sense, constrain the set manipulations we can perform on a plotly object. Below is a simple example of transforming the data underlying a plotly object using &lt;strong&gt;dplyr&lt;/strong&gt;’s &lt;code&gt;mutate()&lt;/code&gt; and &lt;code&gt;filter()&lt;/code&gt; verbs (the plotly book has a whole &lt;a href=&#34;https://cpsievert.github.io/plotly_book/a-case-study-of-housing-sales-in-texas.html#the-data-plot-pipeline&#34;&gt;section on the data-plot-pipeline&lt;/a&gt;, if you’d like to learn more).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(dplyr)
economics %&gt;%
  plot_ly(x = ~date, y = ~unemploy / pop, showlegend = F) %&gt;%
  add_lines(linetype = I(22)) %&gt;%
  mutate(rate = unemploy / pop) %&gt;% 
  slice(which.max(rate)) %&gt;%
  add_markers(symbol = I(10), size = I(50)) %&gt;%
  add_annotations(&#34;peak&#34;)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14559.embed&#34; width=&#34;800&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;p&gt;In this context, I’ve often found it helpful to inspect the (most recent) data associated with a particular plot, which you can do via &lt;code&gt;plotly_data()&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;diamonds %&gt;%
  group_by(cut) %&gt;%
  plot_ly(x = ~price) %&gt;%
  plotly_data()&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## Source: local data frame [53,940 x 10]
## Groups: cut [5]
## 
##    carat       cut color clarity depth table price     x     y     z
##    &lt;dbl&gt;     &lt;ord&gt; &lt;ord&gt;   &lt;ord&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;int&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt;
## 1   0.23     Ideal     E     SI2  61.5    55   326  3.95  3.98  2.43
## 2   0.21   Premium     E     SI1  59.8    61   326  3.89  3.84  2.31
## 3   0.23      Good     E     VS1  56.9    65   327  4.05  4.07  2.31
## 4   0.29   Premium     I     VS2  62.4    58   334  4.20  4.23  2.63
## 5   0.31      Good     J     SI2  63.3    58   335  4.34  4.35  2.75
## 6   0.24 Very Good     J    VVS2  62.8    57   336  3.94  3.96  2.48
## 7   0.24 Very Good     I    VVS1  62.3    57   336  3.95  3.98  2.47
## 8   0.26 Very Good     H     SI1  61.9    55   337  4.07  4.11  2.53
## 9   0.22      Fair     E     VS2  65.1    61   337  3.87  3.78  2.49
## 10  0.23 Very Good     H     VS1  59.4    61   338  4.00  4.05  2.39
## # ... with 53,930 more rows&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To keep up to date with currently supported data manipulation verbs, please consult the &lt;code&gt;help(reexports)&lt;/code&gt; page, and for more examples, check out the examples section under &lt;code&gt;help(plotly_data)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This change in the representation of a plotly object also has important implications for folks using &lt;code&gt;plotly_build()&lt;/code&gt; to “manually” access or modify a plot’s underlying spec. Previously, this function returned the JSON spec as an R list, but it now returns more “meta” information about the htmlwidget, so in order to access that same list, you have to grab the “x” element. The new &lt;code&gt;as_widget()&lt;/code&gt; function (different from the now deprecated &lt;code&gt;as.widget()&lt;/code&gt; function) is designed to turn a plotly spec into an htmlwidget object.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# the style() function provides a more elegant way to do this sort of thing,
# but I know some people like to work with the list object directly...
pl &lt;- plotly_build(qplot(1:10))[[&#34;x&#34;]]
pl$data[[1]]$hoverinfo &lt;- &#34;none&#34;
as_widget(pl)&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&#34;https://plot.ly/~cpsievert/14561.embed&#34; width=&#34;800&#34; height=&#34;300&#34; id=&#34;igraph&#34; scrolling=&#34;no&#34; seamless=&#34;seamless&#34; frameBorder=&#34;0&#34;&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The latest CRAN release upgrades plotly’s R package from version 3.6.0 to 4.5.2. This upgrade includes a number of breaking changes, as well as a ton of new features and bug fixes. The time spent upgrading your code will be worth it as enables &lt;a href=&#34;https://github.com/ropensci/plotly/blob/eae4c9180feb502e30f25fe227c00c0cb02e20a7/NEWS.md#400----13-june-2016&#34;&gt;a ton of new features&lt;/a&gt;. It also provides a better foundation for advancing the &lt;code&gt;plot_ly()&lt;/code&gt; interface (not to mention the &lt;a href=&#34;https://cpsievert.github.io/plotly_book/advanced-interactive-techniques.html&#34;&gt;linked highlighting&lt;/a&gt; stuff we have on tap). This post should provide the information necessary to fix these breaking changes, but if you have any trouble upgrading, please let us know on &lt;a href=&#34;http://community.plot.ly&#34; class=&#34;uri&#34;&gt;http://community.plot.ly&lt;/a&gt;. Happy plotting!&lt;/p&gt;
&lt;/div&gt;

</description>
    </item>
    
    <item>
      <title>3D surface plots of the strikezone</title>
      <link>/2015/06/08/3d-surface-plots-of-the-strikezone.html</link>
      <pubDate>Mon, 08 Jun 2015 00:00:00 +0000</pubDate>
      
      <guid>/2015/06/08/3d-surface-plots-of-the-strikezone.html</guid>
      <description>&lt;script src=&#34;./rmarkdown-libs/htmlwidgets/htmlwidgets.js&#34;&gt;&lt;/script&gt;
&lt;script src=&#34;./rmarkdown-libs/plotly-binding/plotly.js&#34;&gt;&lt;/script&gt;
&lt;script src=&#34;./rmarkdown-libs/typedarray/typedarray.min.js&#34;&gt;&lt;/script&gt;
&lt;script src=&#34;./rmarkdown-libs/jquery/jquery.min.js&#34;&gt;&lt;/script&gt;
&lt;link href=&#34;./rmarkdown-libs/crosstalk/css/crosstalk.css&#34; rel=&#34;stylesheet&#34; /&gt;
&lt;script src=&#34;./rmarkdown-libs/crosstalk/js/crosstalk.min.js&#34;&gt;&lt;/script&gt;
&lt;link href=&#34;./rmarkdown-libs/plotly-htmlwidgets-css/plotly-htmlwidgets.css&#34; rel=&#34;stylesheet&#34; /&gt;
&lt;script src=&#34;./rmarkdown-libs/plotly-main/plotly-latest.min.js&#34;&gt;&lt;/script&gt;


&lt;p&gt;Over the past month, I’ve been working on &lt;a href=&#34;https://github.com/ropensci/plotly&#34;&gt;plotly’s R package&lt;/a&gt;; and in particular, a new interface for creating plotly visualizations from R. I’m really excited about this project and I think it’s one of the most elegant, straight-forward ways to create interactive graphics that are easy to share. In this post, I’ll show you just how easy it is to create 3D surface plots of the strikezone using plotly.&lt;/p&gt;
&lt;div id=&#34;kernel-densities&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Kernel Densities&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;MASS&lt;/strong&gt; package in R has a function called &lt;code&gt;kde2d()&lt;/code&gt; which performs 2D density estimation (with a bivariate normal kernel)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data(pitches, package = &amp;quot;pitchRx&amp;quot;)
dens &amp;lt;- with(pitches, MASS::kde2d(px, pz))&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# plotly isn&amp;#39;t available on CRAN, but u can install from GitHub
# devtools::install_github(&amp;quot;ropensci/plotly@carson-dsl&amp;quot;)
library(plotly)
with(dens, plot_ly(x = x, y = y, z = z, type = &amp;quot;surface&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;htmlwidget-1&#34; style=&#34;width:672px;height:480px;&#34; class=&#34;plotly html-widget&#34;&gt;&lt;/div&gt;
&lt;script type=&#34;application/json&#34; data-for=&#34;htmlwidget-1&#34;&gt;{&#34;x&#34;:{&#34;visdat&#34;:{&#34;173bb2c851e11&#34;:[&#34;function () &#34;,&#34;plotlyVisDat&#34;]},&#34;cur_data&#34;:&#34;173bb2c851e11&#34;,&#34;attrs&#34;:{&#34;173bb2c851e11&#34;:{&#34;x&#34;:[-2.57,-2.35016666666667,-2.13033333333333,-1.9105,-1.69066666666667,-1.47083333333333,-1.251,-1.03116666666667,-0.811333333333333,-0.5915,-0.371666666666667,-0.151833333333333,0.0680000000000001,0.287833333333333,0.507666666666667,0.7275,0.947333333333333,1.16716666666667,1.387,1.60683333333333,1.82666666666667,2.0465,2.26633333333333,2.48616666666667,2.706],&#34;y&#34;:[-0.332,-0.07875,0.1745,0.42775,0.681,0.93425,1.1875,1.44075,1.694,1.94725,2.2005,2.45375,2.707,2.96025,3.2135,3.46675,3.72,3.97325,4.2265,4.47975,4.733,4.98625,5.2395,5.49275,5.746],&#34;z&#34;:[[1.94486550490262e-22,9.05820899635942e-19,1.68662305252932e-15,3.18758255882389e-12,1.07153537801563e-09,4.89365879019289e-08,3.78450939982428e-07,6.62530167924901e-06,0.000364068663763768,0.003421933985244,0.00496597328910233,0.00161514763189889,0.000655095266411036,0.00167526360306156,0.00340085408895158,0.00352956645562639,0.00127503908507418,0.000103628831838848,1.58977833397329e-05,9.9071765224381e-07,8.36335047050154e-09,9.30730124210472e-12,1.38712915421598e-15,2.96122288416002e-20,3.406761284701e-24],[1.40197455954243e-19,6.14169697334107e-16,4.2109834454328e-13,2.32000640889035e-10,7.03446253958646e-08,3.15623108433146e-06,2.16946624630313e-05,5.53217934376366e-05,0.000645960771618455,0.00475168849091251,0.00808297861797341,0.00554301399043084,0.00344367859842939,0.0052471819733525,0.00909283051351779,0.0075363628066226,0.00278877511974145,0.000624581202539905,0.000218025308967713,1.46125559085647e-05,1.33274951864515e-07,1.67362214429255e-10,3.10227271305366e-14,5.86788963180865e-18,2.20351757347874e-20],[3.23724990068862e-17,1.40831980341923e-13,8.03093160801413e-11,1.01038581389775e-08,1.55210964366428e-06,6.66735915747325e-05,0.000429656213455741,0.000723366952082516,0.00165545200198108,0.00789578298428728,0.0158795981224699,0.0157043006157774,0.0100351078037966,0.00977704273159876,0.0134162162525542,0.0105975411536272,0.00530314869320771,0.00265224880576957,0.00113625977859005,8.65322445951924e-05,9.49940019946853e-07,1.61069226038483e-09,1.17125161365094e-12,9.0868961940533e-15,4.73965808049816e-17],[2.41449007934024e-15,1.04216377752384e-11,5.80983905410231e-09,4.46534206940179e-07,1.4379815426864e-05,0.000467294231317575,0.00285555807083459,0.00412231901598428,0.00563671486612448,0.0150249549717106,0.028905080235489,0.0318060683063146,0.0221587318746297,0.0198804306977811,0.0209924970916654,0.0187576059741285,0.0118933678096054,0.00623276531878991,0.00286887229124204,0.000273142379450957,4.25362467998376e-06,2.31406078263687e-08,2.30668986534797e-10,5.96205784270009e-12,3.26738827855137e-14],[6.17390217377862e-14,2.55090067000361e-10,1.38951707139191e-07,9.91544886992095e-06,0.000115417322627143,0.00119841225683334,0.00660622838044079,0.00947366049684737,0.013432986022668,0.0237222205409373,0.0361114518918922,0.0411298718847931,0.038513631449872,0.039639730429876,0.034588891588087,0.0296699174298024,0.0206147169952129,0.0110180794064919,0.00493635822096934,0.000600775953867129,2.49911576305663e-05,7.73310210277741e-07,3.43503907628832e-08,1.29864145197697e-09,7.19625701485179e-12],[7.08224137913998e-13,2.42187359282291e-09,1.17999874746607e-06,7.88679560883438e-05,0.00073284023536415,0.00205191855055047,0.00762200855635267,0.0136155177318802,0.0245893928795013,0.0421409077247095,0.052592244378739,0.0522819848791115,0.0589007362579683,0.0639840834757187,0.0489220893599659,0.0380194563562404,0.0273180767444702,0.0165182861772598,0.00639767947228537,0.00139353512806205,0.00022604395629422,1.6150510035552e-05,2.17172476483719e-06,9.10895798840705e-08,5.06156897559452e-10],[5.54683839835092e-12,1.38810302528187e-08,5.0545160295323e-06,0.000270899607467532,0.00218323551431744,0.00455539908252006,0.0121490315721638,0.0222849364203494,0.0373990672849386,0.0651012684608787,0.0865549234980845,0.0879991524462846,0.0921838693189722,0.0880345965623046,0.0627152268637112,0.0477363829103579,0.0343134737214374,0.0209315368307784,0.00800748468010205,0.00391971036720103,0.0010715548690343,0.00019210877021986,4.75952854706871e-05,2.04379425116725e-06,1.14857059398436e-08],[2.42042973960442e-11,5.32106559478739e-08,1.58605057888914e-05,0.000659987487240921,0.00419182955602604,0.00803497333833688,0.0186606367327213,0.0313315996238675,0.0446340805218208,0.0790179697874303,0.121144174968061,0.131126422683084,0.127101812961371,0.104353117839534,0.0750683835254985,0.059904228152984,0.0416188022338199,0.0247943953858305,0.0118581421579832,0.00747108879510355,0.00261633146464152,0.00116274608464545,0.000341042331505111,1.46682240353917e-05,1.16283600137091e-07],[4.3428218965536e-11,9.57131159060599e-08,2.80415968062358e-05,0.0011130962682008,0.00652354734358377,0.0105107459304788,0.019383841957921,0.0367905086203414,0.0556857756114204,0.0980641305419306,0.147047335400856,0.158211930804006,0.143437832778001,0.114151176818886,0.085281832405814,0.0722380284330549,0.0512501442498922,0.030804873804477,0.017040073538073,0.0120721423855314,0.00576787128362364,0.00305267857754461,0.000807010517446508,3.48646920329664e-05,3.23007697731092e-06],[4.09977549319959e-11,9.44467018979811e-08,2.9137160788271e-05,0.00123196793451247,0.00778201506508134,0.0120343644940001,0.0188917316809787,0.0404636910164624,0.0684592333585217,0.111564285551591,0.158822303395105,0.167858014710074,0.142421478013693,0.123020825780923,0.0973430480381255,0.0870082451087328,0.0700044443049839,0.0431691063967568,0.0222594290903054,0.0165694452179337,0.0115137005796953,0.00476652682998182,0.000762560135493954,5.69630050964745e-05,8.48903532824438e-05],[5.64863425651444e-11,1.16321170963502e-07,3.36631656154679e-05,0.00140197578181981,0.00907610720703086,0.0137979271114078,0.0196507320249154,0.037888702312659,0.0665513118830588,0.103211480580275,0.150964186007225,0.163662728946748,0.148707276144394,0.133082952914503,0.115571428566338,0.104933701923105,0.08936114336543,0.0570210197349577,0.0264328292565989,0.0176627948911594,0.0177561299004007,0.00747156838847413,0.000716357071793947,0.000283915835631553,0.000753354963691705],[1.0728253882957e-10,1.81432519067608e-07,4.25330345953158e-05,0.00145681469048262,0.00843026943180805,0.0141153687513511,0.0191282961291485,0.0300136143828505,0.0530775893509592,0.0843889614501969,0.134600840512132,0.167458196958317,0.175715716462062,0.151731864792361,0.139792829729934,0.122934073854403,0.0998780463750289,0.0663406847099241,0.0320126989417378,0.0204892741939581,0.0219725383309849,0.0100202606531234,0.00110546451712761,0.000794920499945772,0.00213748108140143],[1.01666314731398e-10,1.55784241314551e-07,3.20220622340776e-05,0.000936033860613628,0.00523696439215741,0.0123776759889345,0.016862865136874,0.0240202449201997,0.0464748253332778,0.0807021420276064,0.131855495271966,0.183617987526458,0.212924078769036,0.19018462371817,0.169382614716867,0.139207308242185,0.107781200029961,0.0721890387547594,0.0363465412193483,0.0206308929120999,0.0193108490783355,0.00983411453441234,0.00194779536335789,0.000828884688391069,0.00193746757614308],[1.09329820973751e-10,9.61310487259512e-08,1.34233629358919e-05,0.000312641999847617,0.00191477597547265,0.00693395768110526,0.0132558303759623,0.0270557861561328,0.0575100234355291,0.101758595472878,0.156138213259114,0.216270972253469,0.257116049411387,0.234828135726369,0.197490668444119,0.15348094421114,0.109839040399583,0.0713427798854461,0.0387181548525296,0.0184485659204472,0.015246501079863,0.0100299811907059,0.00369980160463016,0.000580211096286,0.000565522317135138],[8.15278998862128e-10,5.03873153756171e-07,4.06626286386191e-05,0.000456586467118297,0.00139678242274123,0.00541970614164835,0.0154502844200562,0.0378000586949403,0.0741326430860739,0.121751153777242,0.172312591494422,0.230363439814101,0.266730895402626,0.241360642664594,0.198224242406189,0.149395177220942,0.0996775067379294,0.0597177371538926,0.0370241346652716,0.0205673715334376,0.0150452681902388,0.00901137627527405,0.00350761902841751,0.000397952678586922,5.77833971735181e-05],[2.74624461296091e-09,1.70028312311834e-06,0.000138279729392588,0.00158931197099077,0.0042583514029465,0.0104068918457789,0.0231653241159445,0.0464618218863574,0.0847437292848861,0.128135737411035,0.168733527914037,0.214685156331693,0.23838500482843,0.217180366203671,0.171200202309432,0.121974053876656,0.0859021909995411,0.0468491550871453,0.0289549092335559,0.0181356708584234,0.0110572612358182,0.00480316596902594,0.00126533400571846,0.000125726679627271,3.55876797805783e-06],[3.12020321074133e-09,1.96615396973619e-06,0.000169356406643644,0.00228760423193573,0.00800948858765454,0.0174783588686453,0.0320795182921384,0.0546034097615501,0.0860210660767122,0.122486622012254,0.162764365155746,0.192391695636903,0.199889351939613,0.173630280847488,0.123862996949959,0.0821188261987691,0.0582043302836219,0.0306280243789001,0.018223167417485,0.0101729391150521,0.00601482469362366,0.00215246928417329,0.000241967738013273,1.42622706074809e-05,2.3269867537851e-07],[2.48361775741944e-09,1.46412204353492e-06,0.000124579782611106,0.00183425924700307,0.00805857888621526,0.0197888347305013,0.0363471896589006,0.0623528755313438,0.077947453535413,0.0924114083259891,0.124258427659546,0.141762097026223,0.138673949441785,0.112205434083456,0.0782388704235092,0.0529156916076557,0.0332540497936737,0.0172544714833241,0.0105502951828555,0.00490373379455185,0.00345872484632063,0.000972113728977954,5.42125788299995e-05,8.61053669191924e-07,7.95937451428553e-09],[1.51342134881132e-08,2.60290527826408e-06,0.000183126593803456,0.00197994906888459,0.00606808632500794,0.014477745772577,0.0273178110568583,0.0527012232380463,0.0610080138042714,0.0621108783369233,0.0774292498652643,0.0872599243848325,0.0777509196341325,0.0588496877363861,0.0449583384059831,0.0339236283915783,0.0190962439916877,0.0083969702335094,0.00590180231259239,0.00246166224310066,0.00183263243575827,0.000379064851280888,1.26078339755764e-05,7.63182750716343e-08,1.49394958239962e-10],[1.12826387257236e-06,6.21048355088549e-06,0.000203963133622854,0.00200727114017136,0.00507702313271708,0.00890814175375847,0.0138661685184782,0.027773576201284,0.037348432655031,0.0435567454536479,0.0514717047186212,0.0513798878384631,0.0390680809174253,0.0286271092830676,0.0250474389661529,0.0188445070022002,0.010491659204745,0.00308961479727424,0.00221079642365558,0.000798163578526956,0.000448771009699033,8.23042840520462e-05,2.11356283969654e-06,7.90283493561116e-09,5.07106032639216e-12],[4.05834224012983e-05,6.44435433634926e-05,0.000358793474698209,0.00129606855721237,0.00334411086979482,0.00487620140135891,0.0068307907545695,0.0117112282775891,0.0178099047184121,0.0227207959043765,0.026972053065398,0.0246514775900859,0.0183764316845181,0.0143591611480435,0.0132525390339448,0.00896335983862429,0.00582552530302285,0.0012387537542842,0.000384944837152416,0.000115260093240992,3.86232392236697e-05,6.62744131660894e-06,1.59749294086991e-07,5.0834564715025e-10,2.23316558736797e-13],[0.00047905214482304,0.000408756058082303,0.00141448765872271,0.00196148753895072,0.00248516074839662,0.00245075321924254,0.00494308852184594,0.00615160822618376,0.00579511334144655,0.00691296683455517,0.00931640766943761,0.00981343997370129,0.0106469085928544,0.00725994721585735,0.00469833415074846,0.00285322484003017,0.0021763514765506,0.000453657755093486,3.43429005018669e-05,6.39431669319879e-06,1.14185307615841e-06,1.75482637853875e-07,4.16954596727224e-09,1.28352727599786e-11,5.14050988025376e-15],[0.001822999317468,0.00101889471601245,0.00218241803934283,0.00268976221292703,0.00267593031755606,0.00256294764140212,0.00393431827977443,0.00306746984013007,0.00121557095120644,0.00184948175621883,0.00386221444777413,0.00544067156573733,0.00801943123904324,0.00373096207921975,0.000946357340232175,0.000419483459163691,0.000331902158989374,7.2248354831662e-05,2.64629400743431e-06,1.31438636668634e-07,1.21541687204239e-08,1.49705346238237e-09,3.52360656263343e-11,1.07819398063424e-13,4.24427510882887e-17],[0.00222336083233322,0.000976666206566312,0.00109476951957613,0.00128820910299042,0.00133302698896538,0.00194304100727287,0.00205157852105068,0.000808673506325655,0.000532363874398442,0.00185755612070599,0.00316878608744537,0.00392750927487754,0.00487789420449942,0.00162139567347396,0.000137191168062767,2.39563334486873e-05,1.74135794477198e-05,3.91863532741533e-06,1.26545578201811e-07,1.30269307438288e-09,4.96007883026432e-11,4.1250127234568e-12,9.53059438380034e-14,2.91203963755797e-16,1.14289648366549e-19],[0.000866978468613612,0.000338894812277024,0.000180383444329124,0.000198446613935681,0.000235672678421239,0.000559528517758927,0.000526710247699189,0.000128543007615703,0.000685347518889442,0.00252926029377524,0.00227926903352613,0.0019088356121644,0.00198731388631274,0.000530662484983996,2.2440487012024e-05,5.88682521968568e-07,3.01855102802794e-07,6.9277207364183e-08,2.23120568212561e-09,1.10149951141039e-11,8.26016299030163e-14,3.72369308544581e-15,8.23747180416949e-17,2.51363474554799e-19,9.86007034167459e-23]],&#34;alpha_stroke&#34;:1,&#34;sizes&#34;:[10,100],&#34;spans&#34;:[1,20],&#34;type&#34;:&#34;surface&#34;}},&#34;layout&#34;:{&#34;margin&#34;:{&#34;b&#34;:40,&#34;l&#34;:60,&#34;t&#34;:25,&#34;r&#34;:10},&#34;scene&#34;:{&#34;xaxis&#34;:{&#34;title&#34;:[]},&#34;yaxis&#34;:{&#34;title&#34;:[]},&#34;zaxis&#34;:{&#34;title&#34;:[]}},&#34;hovermode&#34;:&#34;closest&#34;,&#34;showlegend&#34;:false,&#34;legend&#34;:{&#34;yanchor&#34;:&#34;top&#34;,&#34;y&#34;:0.5}},&#34;source&#34;:&#34;A&#34;,&#34;config&#34;:{&#34;modeBarButtonsToAdd&#34;:[{&#34;name&#34;:&#34;Collaborate&#34;,&#34;icon&#34;:{&#34;width&#34;:1000,&#34;ascent&#34;:500,&#34;descent&#34;:-50,&#34;path&#34;:&#34;M487 375c7-10 9-23 5-36l-79-259c-3-12-11-23-22-31-11-8-22-12-35-12l-263 0c-15 0-29 5-43 15-13 10-23 23-28 37-5 13-5 25-1 37 0 0 0 3 1 7 1 5 1 8 1 11 0 2 0 4-1 6 0 3-1 5-1 6 1 2 2 4 3 6 1 2 2 4 4 6 2 3 4 5 5 7 5 7 9 16 13 26 4 10 7 19 9 26 0 2 0 5 0 9-1 4-1 6 0 8 0 2 2 5 4 8 3 3 5 5 5 7 4 6 8 15 12 26 4 11 7 19 7 26 1 1 0 4 0 9-1 4-1 7 0 8 1 2 3 5 6 8 4 4 6 6 6 7 4 5 8 13 13 24 4 11 7 20 7 28 1 1 0 4 0 7-1 3-1 6-1 7 0 2 1 4 3 6 1 1 3 4 5 6 2 3 3 5 5 6 1 2 3 5 4 9 2 3 3 7 5 10 1 3 2 6 4 10 2 4 4 7 6 9 2 3 4 5 7 7 3 2 7 3 11 3 3 0 8 0 13-1l0-1c7 2 12 2 14 2l218 0c14 0 25-5 32-16 8-10 10-23 6-37l-79-259c-7-22-13-37-20-43-7-7-19-10-37-10l-248 0c-5 0-9-2-11-5-2-3-2-7 0-12 4-13 18-20 41-20l264 0c5 0 10 2 16 5 5 3 8 6 10 11l85 282c2 5 2 10 2 17 7-3 13-7 17-13z m-304 0c-1-3-1-5 0-7 1-1 3-2 6-2l174 0c2 0 4 1 7 2 2 2 4 4 5 7l6 18c0 3 0 5-1 7-1 1-3 2-6 2l-173 0c-3 0-5-1-8-2-2-2-4-4-4-7z m-24-73c-1-3-1-5 0-7 2-2 3-2 6-2l174 0c2 0 5 0 7 2 3 2 4 4 5 7l6 18c1 2 0 5-1 6-1 2-3 3-5 3l-174 0c-3 0-5-1-7-3-3-1-4-4-5-6z&#34;},&#34;click&#34;:&#34;function(gd) { \n        // is this being viewed in RStudio?\n        if (location.search == &#39;?viewer_pane=1&#39;) {\n          alert(&#39;To learn about plotly for collaboration, visit:\\n https://cpsievert.github.io/plotly_book/plot-ly-for-collaboration.html&#39;);\n        } else {\n          window.open(&#39;https://cpsievert.github.io/plotly_book/plot-ly-for-collaboration.html&#39;, &#39;_blank&#39;);\n        }\n      }&#34;}],&#34;cloud&#34;:false},&#34;data&#34;:[{&#34;colorbar&#34;:{&#34;title&#34;:&#34;&#34;,&#34;ticklen&#34;:2,&#34;len&#34;:0.5,&#34;lenmode&#34;:&#34;fraction&#34;,&#34;y&#34;:1,&#34;yanchor&#34;:&#34;top&#34;},&#34;colorscale&#34;:[[&#34;0&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;3.57311228197746e-13&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;4.09888103921057e-10&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;4.55671574981119e-08&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;1.41884928407398e-06&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;2.3283705254732e-05&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.000152151187210759&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.000720234414276886&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.00179601295942834&#34;,&#34;rgba(68,2,85,1)&#34;],[&#34;0.00364454866584002&#34;,&#34;rgba(68,2,85,1)&#34;],[&#34;0.00620645013575276&#34;,&#34;rgba(68,4,86,1)&#34;],[&#34;0.00857645016518476&#34;,&#34;rgba(69,5,87,1)&#34;],[&#34;0.0139877387416554&#34;,&#34;rgba(69,7,88,1)&#34;],[&#34;0.0211325907994871&#34;,&#34;rgba(69,10,91,1)&#34;],[&#34;0.0302123939337848&#34;,&#34;rgba(70,14,94,1)&#34;],[&#34;0.0431659803125378&#34;,&#34;rgba(70,19,98,1)&#34;],[&#34;0.0632205171111499&#34;,&#34;rgba(71,26,104,1)&#34;],[&#34;0.0784743619563928&#34;,&#34;rgba(72,31,109,1)&#34;],[&#34;0.115490459993311&#34;,&#34;rgba(72,42,121,1)&#34;],[&#34;0.157990350765698&#34;,&#34;rgba(69,55,127,1)&#34;],[&#34;0.224586762109277&#34;,&#34;rgba(62,75,137,1)&#34;],[&#34;0.322055646646682&#34;,&#34;rgba(51,101,142,1)&#34;],[&#34;0.457292559575967&#34;,&#34;rgba(38,133,141,1)&#34;],[&#34;0.59544022133381&#34;,&#34;rgba(41,167,132,1)&#34;],[&#34;1&#34;,&#34;rgba(253,231,37,1)&#34;]],&#34;showscale&#34;:true,&#34;x&#34;:[-2.57,-2.35016666666667,-2.13033333333333,-1.9105,-1.69066666666667,-1.47083333333333,-1.251,-1.03116666666667,-0.811333333333333,-0.5915,-0.371666666666667,-0.151833333333333,0.0680000000000001,0.287833333333333,0.507666666666667,0.7275,0.947333333333333,1.16716666666667,1.387,1.60683333333333,1.82666666666667,2.0465,2.26633333333333,2.48616666666667,2.706],&#34;y&#34;:[-0.332,-0.07875,0.1745,0.42775,0.681,0.93425,1.1875,1.44075,1.694,1.94725,2.2005,2.45375,2.707,2.96025,3.2135,3.46675,3.72,3.97325,4.2265,4.47975,4.733,4.98625,5.2395,5.49275,5.746],&#34;z&#34;:[[1.94486550490262e-22,9.05820899635942e-19,1.68662305252932e-15,3.18758255882389e-12,1.07153537801563e-09,4.89365879019289e-08,3.78450939982428e-07,6.62530167924901e-06,0.000364068663763768,0.003421933985244,0.00496597328910233,0.00161514763189889,0.000655095266411036,0.00167526360306156,0.00340085408895158,0.00352956645562639,0.00127503908507418,0.000103628831838848,1.58977833397329e-05,9.9071765224381e-07,8.36335047050154e-09,9.30730124210472e-12,1.38712915421598e-15,2.96122288416002e-20,3.406761284701e-24],[1.40197455954243e-19,6.14169697334107e-16,4.2109834454328e-13,2.32000640889035e-10,7.03446253958646e-08,3.15623108433146e-06,2.16946624630313e-05,5.53217934376366e-05,0.000645960771618455,0.00475168849091251,0.00808297861797341,0.00554301399043084,0.00344367859842939,0.0052471819733525,0.00909283051351779,0.0075363628066226,0.00278877511974145,0.000624581202539905,0.000218025308967713,1.46125559085647e-05,1.33274951864515e-07,1.67362214429255e-10,3.10227271305366e-14,5.86788963180865e-18,2.20351757347874e-20],[3.23724990068862e-17,1.40831980341923e-13,8.03093160801413e-11,1.01038581389775e-08,1.55210964366428e-06,6.66735915747325e-05,0.000429656213455741,0.000723366952082516,0.00165545200198108,0.00789578298428728,0.0158795981224699,0.0157043006157774,0.0100351078037966,0.00977704273159876,0.0134162162525542,0.0105975411536272,0.00530314869320771,0.00265224880576957,0.00113625977859005,8.65322445951924e-05,9.49940019946853e-07,1.61069226038483e-09,1.17125161365094e-12,9.0868961940533e-15,4.73965808049816e-17],[2.41449007934024e-15,1.04216377752384e-11,5.80983905410231e-09,4.46534206940179e-07,1.4379815426864e-05,0.000467294231317575,0.00285555807083459,0.00412231901598428,0.00563671486612448,0.0150249549717106,0.028905080235489,0.0318060683063146,0.0221587318746297,0.0198804306977811,0.0209924970916654,0.0187576059741285,0.0118933678096054,0.00623276531878991,0.00286887229124204,0.000273142379450957,4.25362467998376e-06,2.31406078263687e-08,2.30668986534797e-10,5.96205784270009e-12,3.26738827855137e-14],[6.17390217377862e-14,2.55090067000361e-10,1.38951707139191e-07,9.91544886992095e-06,0.000115417322627143,0.00119841225683334,0.00660622838044079,0.00947366049684737,0.013432986022668,0.0237222205409373,0.0361114518918922,0.0411298718847931,0.038513631449872,0.039639730429876,0.034588891588087,0.0296699174298024,0.0206147169952129,0.0110180794064919,0.00493635822096934,0.000600775953867129,2.49911576305663e-05,7.73310210277741e-07,3.43503907628832e-08,1.29864145197697e-09,7.19625701485179e-12],[7.08224137913998e-13,2.42187359282291e-09,1.17999874746607e-06,7.88679560883438e-05,0.00073284023536415,0.00205191855055047,0.00762200855635267,0.0136155177318802,0.0245893928795013,0.0421409077247095,0.052592244378739,0.0522819848791115,0.0589007362579683,0.0639840834757187,0.0489220893599659,0.0380194563562404,0.0273180767444702,0.0165182861772598,0.00639767947228537,0.00139353512806205,0.00022604395629422,1.6150510035552e-05,2.17172476483719e-06,9.10895798840705e-08,5.06156897559452e-10],[5.54683839835092e-12,1.38810302528187e-08,5.0545160295323e-06,0.000270899607467532,0.00218323551431744,0.00455539908252006,0.0121490315721638,0.0222849364203494,0.0373990672849386,0.0651012684608787,0.0865549234980845,0.0879991524462846,0.0921838693189722,0.0880345965623046,0.0627152268637112,0.0477363829103579,0.0343134737214374,0.0209315368307784,0.00800748468010205,0.00391971036720103,0.0010715548690343,0.00019210877021986,4.75952854706871e-05,2.04379425116725e-06,1.14857059398436e-08],[2.42042973960442e-11,5.32106559478739e-08,1.58605057888914e-05,0.000659987487240921,0.00419182955602604,0.00803497333833688,0.0186606367327213,0.0313315996238675,0.0446340805218208,0.0790179697874303,0.121144174968061,0.131126422683084,0.127101812961371,0.104353117839534,0.0750683835254985,0.059904228152984,0.0416188022338199,0.0247943953858305,0.0118581421579832,0.00747108879510355,0.00261633146464152,0.00116274608464545,0.000341042331505111,1.46682240353917e-05,1.16283600137091e-07],[4.3428218965536e-11,9.57131159060599e-08,2.80415968062358e-05,0.0011130962682008,0.00652354734358377,0.0105107459304788,0.019383841957921,0.0367905086203414,0.0556857756114204,0.0980641305419306,0.147047335400856,0.158211930804006,0.143437832778001,0.114151176818886,0.085281832405814,0.0722380284330549,0.0512501442498922,0.030804873804477,0.017040073538073,0.0120721423855314,0.00576787128362364,0.00305267857754461,0.000807010517446508,3.48646920329664e-05,3.23007697731092e-06],[4.09977549319959e-11,9.44467018979811e-08,2.9137160788271e-05,0.00123196793451247,0.00778201506508134,0.0120343644940001,0.0188917316809787,0.0404636910164624,0.0684592333585217,0.111564285551591,0.158822303395105,0.167858014710074,0.142421478013693,0.123020825780923,0.0973430480381255,0.0870082451087328,0.0700044443049839,0.0431691063967568,0.0222594290903054,0.0165694452179337,0.0115137005796953,0.00476652682998182,0.000762560135493954,5.69630050964745e-05,8.48903532824438e-05],[5.64863425651444e-11,1.16321170963502e-07,3.36631656154679e-05,0.00140197578181981,0.00907610720703086,0.0137979271114078,0.0196507320249154,0.037888702312659,0.0665513118830588,0.103211480580275,0.150964186007225,0.163662728946748,0.148707276144394,0.133082952914503,0.115571428566338,0.104933701923105,0.08936114336543,0.0570210197349577,0.0264328292565989,0.0176627948911594,0.0177561299004007,0.00747156838847413,0.000716357071793947,0.000283915835631553,0.000753354963691705],[1.0728253882957e-10,1.81432519067608e-07,4.25330345953158e-05,0.00145681469048262,0.00843026943180805,0.0141153687513511,0.0191282961291485,0.0300136143828505,0.0530775893509592,0.0843889614501969,0.134600840512132,0.167458196958317,0.175715716462062,0.151731864792361,0.139792829729934,0.122934073854403,0.0998780463750289,0.0663406847099241,0.0320126989417378,0.0204892741939581,0.0219725383309849,0.0100202606531234,0.00110546451712761,0.000794920499945772,0.00213748108140143],[1.01666314731398e-10,1.55784241314551e-07,3.20220622340776e-05,0.000936033860613628,0.00523696439215741,0.0123776759889345,0.016862865136874,0.0240202449201997,0.0464748253332778,0.0807021420276064,0.131855495271966,0.183617987526458,0.212924078769036,0.19018462371817,0.169382614716867,0.139207308242185,0.107781200029961,0.0721890387547594,0.0363465412193483,0.0206308929120999,0.0193108490783355,0.00983411453441234,0.00194779536335789,0.000828884688391069,0.00193746757614308],[1.09329820973751e-10,9.61310487259512e-08,1.34233629358919e-05,0.000312641999847617,0.00191477597547265,0.00693395768110526,0.0132558303759623,0.0270557861561328,0.0575100234355291,0.101758595472878,0.156138213259114,0.216270972253469,0.257116049411387,0.234828135726369,0.197490668444119,0.15348094421114,0.109839040399583,0.0713427798854461,0.0387181548525296,0.0184485659204472,0.015246501079863,0.0100299811907059,0.00369980160463016,0.000580211096286,0.000565522317135138],[8.15278998862128e-10,5.03873153756171e-07,4.06626286386191e-05,0.000456586467118297,0.00139678242274123,0.00541970614164835,0.0154502844200562,0.0378000586949403,0.0741326430860739,0.121751153777242,0.172312591494422,0.230363439814101,0.266730895402626,0.241360642664594,0.198224242406189,0.149395177220942,0.0996775067379294,0.0597177371538926,0.0370241346652716,0.0205673715334376,0.0150452681902388,0.00901137627527405,0.00350761902841751,0.000397952678586922,5.77833971735181e-05],[2.74624461296091e-09,1.70028312311834e-06,0.000138279729392588,0.00158931197099077,0.0042583514029465,0.0104068918457789,0.0231653241159445,0.0464618218863574,0.0847437292848861,0.128135737411035,0.168733527914037,0.214685156331693,0.23838500482843,0.217180366203671,0.171200202309432,0.121974053876656,0.0859021909995411,0.0468491550871453,0.0289549092335559,0.0181356708584234,0.0110572612358182,0.00480316596902594,0.00126533400571846,0.000125726679627271,3.55876797805783e-06],[3.12020321074133e-09,1.96615396973619e-06,0.000169356406643644,0.00228760423193573,0.00800948858765454,0.0174783588686453,0.0320795182921384,0.0546034097615501,0.0860210660767122,0.122486622012254,0.162764365155746,0.192391695636903,0.199889351939613,0.173630280847488,0.123862996949959,0.0821188261987691,0.0582043302836219,0.0306280243789001,0.018223167417485,0.0101729391150521,0.00601482469362366,0.00215246928417329,0.000241967738013273,1.42622706074809e-05,2.3269867537851e-07],[2.48361775741944e-09,1.46412204353492e-06,0.000124579782611106,0.00183425924700307,0.00805857888621526,0.0197888347305013,0.0363471896589006,0.0623528755313438,0.077947453535413,0.0924114083259891,0.124258427659546,0.141762097026223,0.138673949441785,0.112205434083456,0.0782388704235092,0.0529156916076557,0.0332540497936737,0.0172544714833241,0.0105502951828555,0.00490373379455185,0.00345872484632063,0.000972113728977954,5.42125788299995e-05,8.61053669191924e-07,7.95937451428553e-09],[1.51342134881132e-08,2.60290527826408e-06,0.000183126593803456,0.00197994906888459,0.00606808632500794,0.014477745772577,0.0273178110568583,0.0527012232380463,0.0610080138042714,0.0621108783369233,0.0774292498652643,0.0872599243848325,0.0777509196341325,0.0588496877363861,0.0449583384059831,0.0339236283915783,0.0190962439916877,0.0083969702335094,0.00590180231259239,0.00246166224310066,0.00183263243575827,0.000379064851280888,1.26078339755764e-05,7.63182750716343e-08,1.49394958239962e-10],[1.12826387257236e-06,6.21048355088549e-06,0.000203963133622854,0.00200727114017136,0.00507702313271708,0.00890814175375847,0.0138661685184782,0.027773576201284,0.037348432655031,0.0435567454536479,0.0514717047186212,0.0513798878384631,0.0390680809174253,0.0286271092830676,0.0250474389661529,0.0188445070022002,0.010491659204745,0.00308961479727424,0.00221079642365558,0.000798163578526956,0.000448771009699033,8.23042840520462e-05,2.11356283969654e-06,7.90283493561116e-09,5.07106032639216e-12],[4.05834224012983e-05,6.44435433634926e-05,0.000358793474698209,0.00129606855721237,0.00334411086979482,0.00487620140135891,0.0068307907545695,0.0117112282775891,0.0178099047184121,0.0227207959043765,0.026972053065398,0.0246514775900859,0.0183764316845181,0.0143591611480435,0.0132525390339448,0.00896335983862429,0.00582552530302285,0.0012387537542842,0.000384944837152416,0.000115260093240992,3.86232392236697e-05,6.62744131660894e-06,1.59749294086991e-07,5.0834564715025e-10,2.23316558736797e-13],[0.00047905214482304,0.000408756058082303,0.00141448765872271,0.00196148753895072,0.00248516074839662,0.00245075321924254,0.00494308852184594,0.00615160822618376,0.00579511334144655,0.00691296683455517,0.00931640766943761,0.00981343997370129,0.0106469085928544,0.00725994721585735,0.00469833415074846,0.00285322484003017,0.0021763514765506,0.000453657755093486,3.43429005018669e-05,6.39431669319879e-06,1.14185307615841e-06,1.75482637853875e-07,4.16954596727224e-09,1.28352727599786e-11,5.14050988025376e-15],[0.001822999317468,0.00101889471601245,0.00218241803934283,0.00268976221292703,0.00267593031755606,0.00256294764140212,0.00393431827977443,0.00306746984013007,0.00121557095120644,0.00184948175621883,0.00386221444777413,0.00544067156573733,0.00801943123904324,0.00373096207921975,0.000946357340232175,0.000419483459163691,0.000331902158989374,7.2248354831662e-05,2.64629400743431e-06,1.31438636668634e-07,1.21541687204239e-08,1.49705346238237e-09,3.52360656263343e-11,1.07819398063424e-13,4.24427510882887e-17],[0.00222336083233322,0.000976666206566312,0.00109476951957613,0.00128820910299042,0.00133302698896538,0.00194304100727287,0.00205157852105068,0.000808673506325655,0.000532363874398442,0.00185755612070599,0.00316878608744537,0.00392750927487754,0.00487789420449942,0.00162139567347396,0.000137191168062767,2.39563334486873e-05,1.74135794477198e-05,3.91863532741533e-06,1.26545578201811e-07,1.30269307438288e-09,4.96007883026432e-11,4.1250127234568e-12,9.53059438380034e-14,2.91203963755797e-16,1.14289648366549e-19],[0.000866978468613612,0.000338894812277024,0.000180383444329124,0.000198446613935681,0.000235672678421239,0.000559528517758927,0.000526710247699189,0.000128543007615703,0.000685347518889442,0.00252926029377524,0.00227926903352613,0.0019088356121644,0.00198731388631274,0.000530662484983996,2.2440487012024e-05,5.88682521968568e-07,3.01855102802794e-07,6.9277207364183e-08,2.23120568212561e-09,1.10149951141039e-11,8.26016299030163e-14,3.72369308544581e-15,8.23747180416949e-17,2.51363474554799e-19,9.86007034167459e-23]],&#34;type&#34;:&#34;surface&#34;,&#34;frame&#34;:null}],&#34;highlight&#34;:{&#34;on&#34;:&#34;plotly_click&#34;,&#34;persistent&#34;:false,&#34;dynamic&#34;:false,&#34;selectize&#34;:false,&#34;opacityDim&#34;:0.2,&#34;selected&#34;:{&#34;opacity&#34;:1},&#34;debounce&#34;:0},&#34;base_url&#34;:&#34;https://plot.ly&#34;},&#34;evals&#34;:[&#34;config.modeBarButtonsToAdd.0.click&#34;],&#34;jsHooks&#34;:[]}&lt;/script&gt;
&lt;p&gt;Although this plot is cool, we can’t perform any interesting statistical inference with it. All we can see is an estimated frequency.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;probabilistic-surfaces&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Probabilistic Surfaces&lt;/h3&gt;
&lt;p&gt;Brian Mills and I &lt;a href=&#34;http://princeofslides.blogspot.com/2013/07/advanced-sab-r-metrics-parallelization.html&#34;&gt;have&lt;/a&gt; a &lt;a href=&#34;https://baseballwithr.wordpress.com/2014/04/21/are-umpires-becoming-less-merciful/&#34;&gt;number&lt;/a&gt; &lt;a href=&#34;https://baseballwithr.wordpress.com/2014/10/23/a-probabilistic-model-for-interpreting-strike-zone-expansion-7/&#34;&gt;of&lt;/a&gt; &lt;a href=&#34;http://onlinelibrary.wiley.com/doi/10.1002/mde.2630/abstract&#34;&gt;posts/papers&lt;/a&gt; on using generalized additive models (GAMs) to model event probabilities over the strikezone. To keep things simple, we’ll stick with the example data, and model the probablity of a called strike by allowing it to vary by location and batter stance.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# condition on umpire decisions
noswing &amp;lt;- subset(pitches, des %in% c(&amp;quot;Ball&amp;quot;, &amp;quot;Called Strike&amp;quot;))
noswing$strike &amp;lt;- as.numeric(noswing$des %in% &amp;quot;Called Strike&amp;quot;)
library(mgcv)
m &amp;lt;- bam(strike ~ s(px, pz, by = factor(stand)) + factor(stand), 
         data = noswing, family = binomial(link = &amp;#39;logit&amp;#39;))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;## Warning in attr(pterms[tind[j]], &amp;quot;term.label&amp;quot;): partial match of
## &amp;#39;term.label&amp;#39; to &amp;#39;term.labels&amp;#39;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we use the &lt;code&gt;predict.gam()&lt;/code&gt; method to fit response values (for right handers) over a strike-zone grid.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;px &amp;lt;- round(seq(-2, 2, length.out = 20), 2)
pz &amp;lt;- round(seq(1, 4, length.out = 20), 2)
dat &amp;lt;- expand.grid(px = px, pz = pz, stand = &amp;quot;R&amp;quot;)
dat$fit &amp;lt;- as.numeric(predict(m, dat, type = &amp;quot;response&amp;quot;))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;plotly’s &lt;code&gt;z&lt;/code&gt; argument likes numeric matrices, so we need change the data structure accordingly.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;z &amp;lt;- Reduce(rbind, split(dat$fit, dat$px))
plot_ly(x = px, y = pz, z = z, type = &amp;quot;surface&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;htmlwidget-2&#34; style=&#34;width:672px;height:480px;&#34; class=&#34;plotly html-widget&#34;&gt;&lt;/div&gt;
&lt;script type=&#34;application/json&#34; data-for=&#34;htmlwidget-2&#34;&gt;{&#34;x&#34;:{&#34;visdat&#34;:{&#34;173bb656bf8a2&#34;:[&#34;function () &#34;,&#34;plotlyVisDat&#34;]},&#34;cur_data&#34;:&#34;173bb656bf8a2&#34;,&#34;attrs&#34;:{&#34;173bb656bf8a2&#34;:{&#34;x&#34;:[-2,-1.79,-1.58,-1.37,-1.16,-0.95,-0.74,-0.53,-0.32,-0.11,0.11,0.32,0.53,0.74,0.95,1.16,1.37,1.58,1.79,2],&#34;y&#34;:[1,1.16,1.32,1.47,1.63,1.79,1.95,2.11,2.26,2.42,2.58,2.74,2.89,3.05,3.21,3.37,3.53,3.68,3.84,4],&#34;z&#34;:[[3.57758653526277e-05,8.02205999881526e-05,0.000176264521920287,0.000355341770118825,0.000705038223991468,0.00128051941087968,0.00209173344559967,0.00305705033865498,0.00393759300852239,0.00453870044719242,0.00445378467048278,0.00363482590731713,0.00250583955836422,0.00138912078538691,0.000635864578591468,0.000249392566939524,8.99659342403639e-05,3.41836389671074e-05,1.2578214197928e-05,4.91676808459985e-06],[7.45476426809705e-05,0.00018881802163174,0.000475421237024143,0.00109817279137903,0.00251116482228917,0.00516476498057699,0.00923275049364628,0.0141414929058296,0.0183698791567351,0.0207003497474326,0.0194496669385049,0.0151163445998196,0.00995816928556195,0.00520209838556481,0.00220746940266901,0.000795540731558723,0.000262363781889389,9.23324507736506e-05,3.19965248917357e-05,1.18670305241483e-05],[0.000146980516150693,0.000426534144698078,0.00125769993987692,0.00341919357724018,0.00927938085678559,0.0221237895075691,0.0437710790427745,0.0695360190887174,0.0880613560705054,0.0930668617350125,0.0817287666037524,0.0603759565696069,0.0386517983426933,0.0198460835107981,0.00828026169895449,0.00289811970650278,0.000910537132773933,0.000301486092340666,9.82258090829316e-05,3.42785403883539e-05],[0.000263391803696946,0.000879185855414019,0.00306572843113868,0.00991848122889885,0.0324953171506848,0.0899393533414943,0.189710631450948,0.293825494896133,0.350384975134003,0.349837855311724,0.298442900852794,0.221082574181478,0.147166311005702,0.0808769963252809,0.0360298355850917,0.0130256013277491,0.00404393480909955,0.00127023773431883,0.000374397253609033,0.000117263919882019],[0.000410570632702244,0.00153831207350856,0.00621254697699296,0.0236066855896623,0.0909798563463804,0.269779294311879,0.519490721145432,0.693596390766163,0.760035062572818,0.76008919995028,0.705364189415507,0.60343002739232,0.479254935169088,0.325194153003412,0.174008863702939,0.0694645942403275,0.0215990048680598,0.00632893860346117,0.00164266770869171,0.000440766654106314],[0.000550086949746066,0.00221463473019121,0.0098548669047862,0.0418975814183604,0.178474452678935,0.500561600416987,0.790253285676421,0.90996508601168,0.944766814443165,0.951157627529971,0.940291816716226,0.911372060637796,0.861411865945184,0.762671690828348,0.576612303673157,0.312250552415589,0.108696401579869,0.0303001579550384,0.00686894427019312,0.00155118142068533],[0.000662323949437627,0.00275874308304829,0.0128482689507254,0.057676239129333,0.255781646740576,0.656413047738159,0.900800985042257,0.969088109228592,0.985411658069384,0.989816774631418,0.989354751720544,0.985204765836354,0.975942616674969,0.951748557733086,0.883459852607341,0.691239857177363,0.342489519184858,0.103207131410501,0.0212363510731235,0.00414402007279662],[0.000782956800346974,0.00332535618657425,0.0159071236788277,0.0725089571313433,0.31725605365325,0.740927499366802,0.940199306955872,0.984986205031962,0.994258483896883,0.996761701915689,0.997145331208867,0.996389717596721,0.994139508425889,0.98711407436753,0.962390280803032,0.865632419916952,0.561892651118016,0.198035234255799,0.0393551793515531,0.00701847733993338],[0.000980757011997766,0.00431819028419709,0.0214925122305598,0.0998159341678252,0.401953656565063,0.807426895189325,0.959700270388346,0.990633271296678,0.996704228209915,0.998327429842266,0.998662100932272,0.998380781714803,0.997278896804068,0.993383342865941,0.977732968535457,0.905177384232212,0.624559565846533,0.224028601042125,0.0420744972554509,0.00715032744909287],[0.0013045152930447,0.00614119169872362,0.0324370761807817,0.151791932364619,0.527535726721571,0.873487918887376,0.974101616056351,0.993720062819199,0.997689505561404,0.998787621480355,0.999003089395574,0.998737777703933,0.997721313507065,0.993833403822684,0.97668382031147,0.890442173696708,0.563223016507242,0.173940757221603,0.0299530906871785,0.00499240269487706],[0.00172717305992397,0.00873963412947238,0.0490931789273127,0.226106287868796,0.654716180813954,0.920060849271263,0.983012860233137,0.995337221323391,0.998031402920099,0.998807682086954,0.998890950680399,0.998447619085164,0.996974032263334,0.991213983022013,0.96483518436645,0.834296369210703,0.434841253452042,0.110364072621274,0.0177704338297444,0.00292534511363774],[0.00195936934746731,0.010220431359986,0.0584444586621547,0.264662982850822,0.702064757203795,0.932526708294502,0.984347019850887,0.994957213186529,0.997473138571126,0.998177359163431,0.998061655614383,0.997066012593422,0.99414876053113,0.983361593383074,0.937413520067367,0.742121972398241,0.313184479796472,0.0699267477619188,0.0109825346489566,0.00179210476498614],[0.00164371976720049,0.00827577239019195,0.0457081192111495,0.209502536500128,0.619292434849989,0.896910730560894,0.971969146664769,0.989256313460639,0.993632111918298,0.994646547745293,0.993780128719159,0.990525269357135,0.982322160136238,0.956165032637728,0.865595103779702,0.588397288605818,0.202912350813965,0.0434669922822153,0.0070246392463882,0.00118259263191325],[0.000943377399739131,0.0041983547014355,0.0205132534055921,0.091126176421647,0.344690485602433,0.705233489550625,0.890154037334157,0.94837323539417,0.964511374084361,0.967004814185687,0.960910520907761,0.944821320378604,0.912299749422983,0.833263212718884,0.65012935165063,0.339348933151486,0.100794986550144,0.0229716071134752,0.0041612431591555,0.000770093692625262],[0.000380167362587331,0.00138758264624787,0.00547746313662126,0.0208280068328676,0.0824647411280159,0.251433754267107,0.48918181085693,0.653388745638194,0.715354458157425,0.718145815444073,0.682272093559275,0.618377662503397,0.531504996113593,0.401791841279196,0.242420939307172,0.104973911417611,0.0326287158346794,0.00883967688062923,0.00196156120964452,0.000427122764345633],[0.000121383475541741,0.000355129674703374,0.0010987583018799,0.00334834073666019,0.0110959321849997,0.0331029661129281,0.0768544936959685,0.1272977154237,0.15351665620631,0.150765394010648,0.13034337719123,0.10632986147561,0.0845208030668901,0.0606419983856303,0.036988957570883,0.0180134986006498,0.00694322147082822,0.00238877602260558,0.000678457084873071,0.000182866314534655],[3.59181144901063e-05,8.7550713696409e-05,0.000220347026280471,0.000546122787189098,0.00147207372739153,0.00370592328765444,0.00769026039473285,0.0120598808462887,0.0141216602241,0.0134300515793909,0.0113302927620253,0.00921965702614787,0.00751711360099247,0.00574364429763232,0.00395199531830455,0.00231896743181707,0.00113163513299179,0.000493054032234065,0.000179392562839505,6.07115235223008e-05],[1.08369373872196e-05,2.3147009811202e-05,5.03992671138667e-05,0.000106593707730633,0.000237592300012343,0.000496779149103315,0.000889060432302605,0.00126435393996673,0.00140440421131564,0.00130416616851723,0.00109290579922194,0.000887590857358267,0.000729291279323174,0.000575755787551856,0.000429631366132553,0.000289198751113054,0.000169477222136809,9.0019443364255e-05,4.07307852020344e-05,1.69687071111408e-05],[3.3860915686541e-06,6.51424889752424e-06,1.26028424301529e-05,2.33863482638006e-05,4.42539316442965e-05,7.80355262537118e-05,0.000120985403922715,0.000156876388666035,0.000167527687692359,0.000154665876884462,0.000130662075684365,0.000106874406740694,8.78029047295152e-05,7.04215789863604e-05,5.5069145257435e-05,4.0372346775901e-05,2.6789188722343e-05,1.64513411458274e-05,8.83909940726204e-06,4.37530423436634e-06],[1.08350403035557e-06,1.90146555929556e-06,3.30655766461319e-06,5.45563867444077e-06,8.95810877784895e-06,1.36997059883148e-05,1.88216399482001e-05,2.25911389077143e-05,2.35431609019108e-05,2.19080006673469e-05,1.887855492609e-05,1.57190748266523e-05,1.3133578537934e-05,1.08003843841468e-05,8.70030304390008e-06,6.69518511506208e-06,4.79878896382143e-06,3.25061962543499e-06,1.97723118537716e-06,1.11800688317123e-06]],&#34;alpha_stroke&#34;:1,&#34;sizes&#34;:[10,100],&#34;spans&#34;:[1,20],&#34;type&#34;:&#34;surface&#34;}},&#34;layout&#34;:{&#34;margin&#34;:{&#34;b&#34;:40,&#34;l&#34;:60,&#34;t&#34;:25,&#34;r&#34;:10},&#34;scene&#34;:{&#34;xaxis&#34;:{&#34;title&#34;:[]},&#34;yaxis&#34;:{&#34;title&#34;:[]},&#34;zaxis&#34;:{&#34;title&#34;:[]}},&#34;hovermode&#34;:&#34;closest&#34;,&#34;showlegend&#34;:false,&#34;legend&#34;:{&#34;yanchor&#34;:&#34;top&#34;,&#34;y&#34;:0.5}},&#34;source&#34;:&#34;A&#34;,&#34;config&#34;:{&#34;modeBarButtonsToAdd&#34;:[{&#34;name&#34;:&#34;Collaborate&#34;,&#34;icon&#34;:{&#34;width&#34;:1000,&#34;ascent&#34;:500,&#34;descent&#34;:-50,&#34;path&#34;:&#34;M487 375c7-10 9-23 5-36l-79-259c-3-12-11-23-22-31-11-8-22-12-35-12l-263 0c-15 0-29 5-43 15-13 10-23 23-28 37-5 13-5 25-1 37 0 0 0 3 1 7 1 5 1 8 1 11 0 2 0 4-1 6 0 3-1 5-1 6 1 2 2 4 3 6 1 2 2 4 4 6 2 3 4 5 5 7 5 7 9 16 13 26 4 10 7 19 9 26 0 2 0 5 0 9-1 4-1 6 0 8 0 2 2 5 4 8 3 3 5 5 5 7 4 6 8 15 12 26 4 11 7 19 7 26 1 1 0 4 0 9-1 4-1 7 0 8 1 2 3 5 6 8 4 4 6 6 6 7 4 5 8 13 13 24 4 11 7 20 7 28 1 1 0 4 0 7-1 3-1 6-1 7 0 2 1 4 3 6 1 1 3 4 5 6 2 3 3 5 5 6 1 2 3 5 4 9 2 3 3 7 5 10 1 3 2 6 4 10 2 4 4 7 6 9 2 3 4 5 7 7 3 2 7 3 11 3 3 0 8 0 13-1l0-1c7 2 12 2 14 2l218 0c14 0 25-5 32-16 8-10 10-23 6-37l-79-259c-7-22-13-37-20-43-7-7-19-10-37-10l-248 0c-5 0-9-2-11-5-2-3-2-7 0-12 4-13 18-20 41-20l264 0c5 0 10 2 16 5 5 3 8 6 10 11l85 282c2 5 2 10 2 17 7-3 13-7 17-13z m-304 0c-1-3-1-5 0-7 1-1 3-2 6-2l174 0c2 0 4 1 7 2 2 2 4 4 5 7l6 18c0 3 0 5-1 7-1 1-3 2-6 2l-173 0c-3 0-5-1-8-2-2-2-4-4-4-7z m-24-73c-1-3-1-5 0-7 2-2 3-2 6-2l174 0c2 0 5 0 7 2 3 2 4 4 5 7l6 18c1 2 0 5-1 6-1 2-3 3-5 3l-174 0c-3 0-5-1-7-3-3-1-4-4-5-6z&#34;},&#34;click&#34;:&#34;function(gd) { \n        // is this being viewed in RStudio?\n        if (location.search == &#39;?viewer_pane=1&#39;) {\n          alert(&#39;To learn about plotly for collaboration, visit:\\n https://cpsievert.github.io/plotly_book/plot-ly-for-collaboration.html&#39;);\n        } else {\n          window.open(&#39;https://cpsievert.github.io/plotly_book/plot-ly-for-collaboration.html&#39;, &#39;_blank&#39;);\n        }\n      }&#34;}],&#34;cloud&#34;:false},&#34;data&#34;:[{&#34;colorbar&#34;:{&#34;title&#34;:&#34;&#34;,&#34;ticklen&#34;:2,&#34;len&#34;:0.5,&#34;lenmode&#34;:&#34;fraction&#34;,&#34;y&#34;:1,&#34;yanchor&#34;:&#34;top&#34;},&#34;colorscale&#34;:[[&#34;0&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;9.74945588024089e-06&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;2.70344990050677e-05&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;8.67744772370683e-05&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.000176921605069058&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.000426778758224965&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.000858047396666489&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.00133591528204641&#34;,&#34;rgba(68,2,84,1)&#34;],[&#34;0.00239007780214052&#34;,&#34;rgba(68,2,85,1)&#34;],[&#34;0.00415785050805144&#34;,&#34;rgba(68,3,85,1)&#34;],[&#34;0.0070620256530295&#34;,&#34;rgba(68,4,86,1)&#34;],[&#34;0.0113112026995204&#34;,&#34;rgba(69,6,88,1)&#34;],[&#34;0.0210521053260512&#34;,&#34;rgba(69,10,91,1)&#34;],[&#34;0.0419604887144914&#34;,&#34;rgba(70,19,97,1)&#34;],[&#34;0.0823618606446044&#34;,&#34;rgba(72,32,110,1)&#34;],[&#34;0.148663248674848&#34;,&#34;rgba(70,52,126,1)&#34;],[&#34;0.264926294227606&#34;,&#34;rgba(59,86,139,1)&#34;],[&#34;0.485943117338107&#34;,&#34;rgba(37,140,140,1)&#34;],[&#34;0.663538933635908&#34;,&#34;rgba(53,182,121,1)&#34;],[&#34;0.834999465692521&#34;,&#34;rgba(148,214,69,1)&#34;],[&#34;0.939743188172847&#34;,&#34;rgba(214,227,41,1)&#34;],[&#34;0.975304005280872&#34;,&#34;rgba(237,229,39,1)&#34;],[&#34;0.992057789415734&#34;,&#34;rgba(248,230,38,1)&#34;],[&#34;0.998090762270634&#34;,&#34;rgba(252,231,37,1)&#34;],[&#34;1&#34;,&#34;rgba(253,231,37,1)&#34;]],&#34;showscale&#34;:true,&#34;x&#34;:[-2,-1.79,-1.58,-1.37,-1.16,-0.95,-0.74,-0.53,-0.32,-0.11,0.11,0.32,0.53,0.74,0.95,1.16,1.37,1.58,1.79,2],&#34;y&#34;:[1,1.16,1.32,1.47,1.63,1.79,1.95,2.11,2.26,2.42,2.58,2.74,2.89,3.05,3.21,3.37,3.53,3.68,3.84,4],&#34;z&#34;:[[3.57758653526277e-05,8.02205999881526e-05,0.000176264521920287,0.000355341770118825,0.000705038223991468,0.00128051941087968,0.00209173344559967,0.00305705033865498,0.00393759300852239,0.00453870044719242,0.00445378467048278,0.00363482590731713,0.00250583955836422,0.00138912078538691,0.000635864578591468,0.000249392566939524,8.99659342403639e-05,3.41836389671074e-05,1.2578214197928e-05,4.91676808459985e-06],[7.45476426809705e-05,0.00018881802163174,0.000475421237024143,0.00109817279137903,0.00251116482228917,0.00516476498057699,0.00923275049364628,0.0141414929058296,0.0183698791567351,0.0207003497474326,0.0194496669385049,0.0151163445998196,0.00995816928556195,0.00520209838556481,0.00220746940266901,0.000795540731558723,0.000262363781889389,9.23324507736506e-05,3.19965248917357e-05,1.18670305241483e-05],[0.000146980516150693,0.000426534144698078,0.00125769993987692,0.00341919357724018,0.00927938085678559,0.0221237895075691,0.0437710790427745,0.0695360190887174,0.0880613560705054,0.0930668617350125,0.0817287666037524,0.0603759565696069,0.0386517983426933,0.0198460835107981,0.00828026169895449,0.00289811970650278,0.000910537132773933,0.000301486092340666,9.82258090829316e-05,3.42785403883539e-05],[0.000263391803696946,0.000879185855414019,0.00306572843113868,0.00991848122889885,0.0324953171506848,0.0899393533414943,0.189710631450948,0.293825494896133,0.350384975134003,0.349837855311724,0.298442900852794,0.221082574181478,0.147166311005702,0.0808769963252809,0.0360298355850917,0.0130256013277491,0.00404393480909955,0.00127023773431883,0.000374397253609033,0.000117263919882019],[0.000410570632702244,0.00153831207350856,0.00621254697699296,0.0236066855896623,0.0909798563463804,0.269779294311879,0.519490721145432,0.693596390766163,0.760035062572818,0.76008919995028,0.705364189415507,0.60343002739232,0.479254935169088,0.325194153003412,0.174008863702939,0.0694645942403275,0.0215990048680598,0.00632893860346117,0.00164266770869171,0.000440766654106314],[0.000550086949746066,0.00221463473019121,0.0098548669047862,0.0418975814183604,0.178474452678935,0.500561600416987,0.790253285676421,0.90996508601168,0.944766814443165,0.951157627529971,0.940291816716226,0.911372060637796,0.861411865945184,0.762671690828348,0.576612303673157,0.312250552415589,0.108696401579869,0.0303001579550384,0.00686894427019312,0.00155118142068533],[0.000662323949437627,0.00275874308304829,0.0128482689507254,0.057676239129333,0.255781646740576,0.656413047738159,0.900800985042257,0.969088109228592,0.985411658069384,0.989816774631418,0.989354751720544,0.985204765836354,0.975942616674969,0.951748557733086,0.883459852607341,0.691239857177363,0.342489519184858,0.103207131410501,0.0212363510731235,0.00414402007279662],[0.000782956800346974,0.00332535618657425,0.0159071236788277,0.0725089571313433,0.31725605365325,0.740927499366802,0.940199306955872,0.984986205031962,0.994258483896883,0.996761701915689,0.997145331208867,0.996389717596721,0.994139508425889,0.98711407436753,0.962390280803032,0.865632419916952,0.561892651118016,0.198035234255799,0.0393551793515531,0.00701847733993338],[0.000980757011997766,0.00431819028419709,0.0214925122305598,0.0998159341678252,0.401953656565063,0.807426895189325,0.959700270388346,0.990633271296678,0.996704228209915,0.998327429842266,0.998662100932272,0.998380781714803,0.997278896804068,0.993383342865941,0.977732968535457,0.905177384232212,0.624559565846533,0.224028601042125,0.0420744972554509,0.00715032744909287],[0.0013045152930447,0.00614119169872362,0.0324370761807817,0.151791932364619,0.527535726721571,0.873487918887376,0.974101616056351,0.993720062819199,0.997689505561404,0.998787621480355,0.999003089395574,0.998737777703933,0.997721313507065,0.993833403822684,0.97668382031147,0.890442173696708,0.563223016507242,0.173940757221603,0.0299530906871785,0.00499240269487706],[0.00172717305992397,0.00873963412947238,0.0490931789273127,0.226106287868796,0.654716180813954,0.920060849271263,0.983012860233137,0.995337221323391,0.998031402920099,0.998807682086954,0.998890950680399,0.998447619085164,0.996974032263334,0.991213983022013,0.96483518436645,0.834296369210703,0.434841253452042,0.110364072621274,0.0177704338297444,0.00292534511363774],[0.00195936934746731,0.010220431359986,0.0584444586621547,0.264662982850822,0.702064757203795,0.932526708294502,0.984347019850887,0.994957213186529,0.997473138571126,0.998177359163431,0.998061655614383,0.997066012593422,0.99414876053113,0.983361593383074,0.937413520067367,0.742121972398241,0.313184479796472,0.0699267477619188,0.0109825346489566,0.00179210476498614],[0.00164371976720049,0.00827577239019195,0.0457081192111495,0.209502536500128,0.619292434849989,0.896910730560894,0.971969146664769,0.989256313460639,0.993632111918298,0.994646547745293,0.993780128719159,0.990525269357135,0.982322160136238,0.956165032637728,0.865595103779702,0.588397288605818,0.202912350813965,0.0434669922822153,0.0070246392463882,0.00118259263191325],[0.000943377399739131,0.0041983547014355,0.0205132534055921,0.091126176421647,0.344690485602433,0.705233489550625,0.890154037334157,0.94837323539417,0.964511374084361,0.967004814185687,0.960910520907761,0.944821320378604,0.912299749422983,0.833263212718884,0.65012935165063,0.339348933151486,0.100794986550144,0.0229716071134752,0.0041612431591555,0.000770093692625262],[0.000380167362587331,0.00138758264624787,0.00547746313662126,0.0208280068328676,0.0824647411280159,0.251433754267107,0.48918181085693,0.653388745638194,0.715354458157425,0.718145815444073,0.682272093559275,0.618377662503397,0.531504996113593,0.401791841279196,0.242420939307172,0.104973911417611,0.0326287158346794,0.00883967688062923,0.00196156120964452,0.000427122764345633],[0.000121383475541741,0.000355129674703374,0.0010987583018799,0.00334834073666019,0.0110959321849997,0.0331029661129281,0.0768544936959685,0.1272977154237,0.15351665620631,0.150765394010648,0.13034337719123,0.10632986147561,0.0845208030668901,0.0606419983856303,0.036988957570883,0.0180134986006498,0.00694322147082822,0.00238877602260558,0.000678457084873071,0.000182866314534655],[3.59181144901063e-05,8.7550713696409e-05,0.000220347026280471,0.000546122787189098,0.00147207372739153,0.00370592328765444,0.00769026039473285,0.0120598808462887,0.0141216602241,0.0134300515793909,0.0113302927620253,0.00921965702614787,0.00751711360099247,0.00574364429763232,0.00395199531830455,0.00231896743181707,0.00113163513299179,0.000493054032234065,0.000179392562839505,6.07115235223008e-05],[1.08369373872196e-05,2.3147009811202e-05,5.03992671138667e-05,0.000106593707730633,0.000237592300012343,0.000496779149103315,0.000889060432302605,0.00126435393996673,0.00140440421131564,0.00130416616851723,0.00109290579922194,0.000887590857358267,0.000729291279323174,0.000575755787551856,0.000429631366132553,0.000289198751113054,0.000169477222136809,9.0019443364255e-05,4.07307852020344e-05,1.69687071111408e-05],[3.3860915686541e-06,6.51424889752424e-06,1.26028424301529e-05,2.33863482638006e-05,4.42539316442965e-05,7.80355262537118e-05,0.000120985403922715,0.000156876388666035,0.000167527687692359,0.000154665876884462,0.000130662075684365,0.000106874406740694,8.78029047295152e-05,7.04215789863604e-05,5.5069145257435e-05,4.0372346775901e-05,2.6789188722343e-05,1.64513411458274e-05,8.83909940726204e-06,4.37530423436634e-06],[1.08350403035557e-06,1.90146555929556e-06,3.30655766461319e-06,5.45563867444077e-06,8.95810877784895e-06,1.36997059883148e-05,1.88216399482001e-05,2.25911389077143e-05,2.35431609019108e-05,2.19080006673469e-05,1.887855492609e-05,1.57190748266523e-05,1.3133578537934e-05,1.08003843841468e-05,8.70030304390008e-06,6.69518511506208e-06,4.79878896382143e-06,3.25061962543499e-06,1.97723118537716e-06,1.11800688317123e-06]],&#34;type&#34;:&#34;surface&#34;,&#34;frame&#34;:null}],&#34;highlight&#34;:{&#34;on&#34;:&#34;plotly_click&#34;,&#34;persistent&#34;:false,&#34;dynamic&#34;:false,&#34;selectize&#34;:false,&#34;opacityDim&#34;:0.2,&#34;selected&#34;:{&#34;opacity&#34;:1},&#34;debounce&#34;:0},&#34;base_url&#34;:&#34;https://plot.ly&#34;},&#34;evals&#34;:[&#34;config.modeBarButtonsToAdd.0.click&#34;],&#34;jsHooks&#34;:[]}&lt;/script&gt;
&lt;p&gt;It’s more interesting to look at the difference in fitted values for right/left handed batters:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;dat2 &amp;lt;- expand.grid(px = px, pz = pz, stand = &amp;quot;L&amp;quot;)
dat2$fit &amp;lt;- as.numeric(predict(m, dat2, type = &amp;quot;response&amp;quot;))
z &amp;lt;- Reduce(rbind, split(dat2$fit - dat$fit, dat2$px))
plot_ly(x = px, y = pz, z = z, type = &amp;quot;surface&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;htmlwidget-3&#34; style=&#34;width:672px;height:480px;&#34; class=&#34;plotly html-widget&#34;&gt;&lt;/div&gt;
&lt;script type=&#34;application/json&#34; data-for=&#34;htmlwidget-3&#34;&gt;{&#34;x&#34;:{&#34;visdat&#34;:{&#34;173bb49ad117&#34;:[&#34;function () &#34;,&#34;plotlyVisDat&#34;]},&#34;cur_data&#34;:&#34;173bb49ad117&#34;,&#34;attrs&#34;:{&#34;173bb49ad117&#34;:{&#34;x&#34;:[-2,-1.79,-1.58,-1.37,-1.16,-0.95,-0.74,-0.53,-0.32,-0.11,0.11,0.32,0.53,0.74,0.95,1.16,1.37,1.58,1.79,2],&#34;y&#34;:[1,1.16,1.32,1.47,1.63,1.79,1.95,2.11,2.26,2.42,2.58,2.74,2.89,3.05,3.21,3.37,3.53,3.68,3.84,4],&#34;z&#34;:[[-3.08284008087714e-05,-6.95055940568146e-05,-0.000152904027610235,-0.000307129199374622,-0.000603336168575354,-0.00107670984843562,-0.00171226369910043,-0.00240874880915773,-0.00295427971153382,-0.00317054647237388,-0.00280952926875751,-0.00196172588475186,-0.00105272569205216,-0.000323960230125378,3.3549517257131e-05,0.000119852559708508,9.61356667690334e-05,5.93721460353743e-05,3.14647681138379e-05,1.58029588207999e-05],[-5.97156266493559e-05,-0.000153088494010707,-0.000387532509628423,-0.000892669522760702,-0.00201640602902329,-0.00404594278989958,-0.00694463181537447,-0.0100057275690944,-0.0119859163758925,-0.0120283711265685,-0.00963624282410412,-0.00596704209154539,-0.0027515914658741,-0.000500846134559077,0.000407598238072749,0.000485581898026756,0.000314646517954195,0.00017103347008332,8.14107830552762e-05,3.74192813287609e-05],[-0.000101627444198409,-0.000301333344533462,-0.000898232088150826,-0.00243441431990618,-0.00649152053922412,-0.0148271879411579,-0.0270315112680516,-0.0374449983586466,-0.0388283465029169,-0.0301817925468875,-0.0172263230031702,-0.00669034984812925,-0.000870561914488886,0.00197750252074761,0.00247649598670947,0.0017710714655731,0.000958124344365332,0.000465610152993699,0.000200220993096641,8.42640062574887e-05],[-0.000128604814171655,-0.000440962030265253,-0.00155556773743255,-0.00500072802176085,-0.0157830111718607,-0.0391865565630043,-0.0647058718962745,-0.0609209903888678,-0.0254246635216605,0.0213731248005544,0.0534323534931901,0.0585823014166358,0.0431002715194586,0.0233890346548393,0.0112657309475754,0.00536020986347699,0.00244888257448314,0.00109063688426224,0.000433192231197526,0.000168959269380315],[-5.35787512105406e-05,-0.000193725916699136,-0.00071984763234496,-0.0024665516752808,-0.00778338414064364,-0.012488888790418,0.00340487085142471,0.0311296079758335,0.05350697699951,0.0789604373028631,0.110144124880591,0.135517408579247,0.125777800734419,0.0746467025094918,0.0237011900823417,0.00439954121958033,0.00155828023525468,0.0010060193941622,0.000519537398411164,0.000229323435681202],[0.000231187815892094,0.001028155057528,0.00502128173702423,0.0212756208079204,0.0704210591732029,0.0977754338871877,0.0567650663573196,0.0287994202941217,0.0207097317586338,0.0210550455213916,0.0272621222368635,0.0375816297686179,0.0429088025060582,0.0243759868905198,-0.0339139628664195,-0.0667488876179007,-0.0338886493262537,-0.00941088994414349,-0.00158339329012525,-0.000124375679941646],[0.00070578158234531,0.00308469810879412,0.0148390754014889,0.0603446183305194,0.158085461671079,0.120993118275384,0.0344675790372146,0.00895908781060817,0.00376636964951738,0.00263854377365913,0.00275033737207775,0.00303010403258119,0.0014060992193039,-0.0106638613391351,-0.0623415435232483,-0.171239414769716,-0.157662323002819,-0.0547482261896157,-0.0104792384390633,-0.00156445878855624],[0.00120944757675567,0.00486009816118491,0.0211982602675762,0.0763932627174608,0.156562830023083,0.0749392028484107,0.00931695344184547,-0.000725702764466818,-0.00112352766913981,-0.000814975010736241,-0.000724799687275901,-0.00106850056599106,-0.00254558529782112,-0.0091595944462225,-0.0391632896923689,-0.147201645441264,-0.242701444321522,-0.113028054189369,-0.0220315040480563,-0.00318557016571292],[0.00165831211253587,0.00573397409548176,0.0204513098643157,0.0552441223744598,0.0605286462669303,-0.0109402112716294,-0.0184175748033502,-0.00868525484471916,-0.00406681240455165,-0.00216461692358394,-0.00156985252088404,-0.00168185358762074,-0.00270702471789352,-0.00694636680186433,-0.0254332208122677,-0.101398748786627,-0.210608338195858,-0.108496962426006,-0.0193501526756375,-0.00229105376373718],[0.00214515762113703,0.00605151361716245,0.0142834428257491,0.00674421627782487,-0.0830113252545907,-0.104858459313984,-0.0476060072654318,-0.0175903928185844,-0.00759174625326553,-0.0038223778548131,-0.00257082153042831,-0.00245700686990069,-0.00337887120162972,-0.00696578141044912,-0.0200801305250857,-0.0647989988406206,-0.108396035876376,-0.0396756946025495,-0.00308192377742362,0.000768520651872757],[0.00301304479020884,0.00681254510602234,0.0055508380609301,-0.0571935625061334,-0.215428108293704,-0.176014098844575,-0.0756923613543237,-0.0297333317385063,-0.0138501640242414,-0.00748645788525681,-0.00522110526972275,-0.00490329419256497,-0.00617291659174912,-0.0104697651230012,-0.0207758523975696,-0.0294517158765599,0.0151969820943215,0.0330428054852378,0.0132472849620316,0.00395833240047616],[0.00463593912761808,0.00972250936398574,0.0043930538171191,-0.0889604124015716,-0.278894733719207,-0.227989726920128,-0.112066633187088,-0.0529076410222092,-0.0294426698025584,-0.0188705628285204,-0.0147931356898146,-0.0144531942736155,-0.0174126729827905,-0.0253946861288933,-0.0370869908410733,-0.0116445645923879,0.0834706357003315,0.0664926685923611,0.0221519578073514,0.00613653868161607],[0.0066687942498245,0.0145874746775531,0.0181229949498726,-0.0499544791683562,-0.261888734053365,-0.29697713307906,-0.197186187941246,-0.124755218146359,-0.0900046015882122,-0.0730233791421587,-0.0667928865377894,-0.0681547654381852,-0.0765354411799265,-0.0931937042562118,-0.101293199597434,-0.0260221675561215,0.0861332499646646,0.064934059311413,0.0237095132839148,0.0071690876821971],[0.0077514196660788,0.0170267426883395,0.030763057913854,0.0207645900610317,-0.116122910138168,-0.32123767976706,-0.369066409714513,-0.345711278582948,-0.331317336368753,-0.332148161327558,-0.337239992428577,-0.33731896888062,-0.328679337590278,-0.298793774248079,-0.208876179406422,-0.0405068102057163,0.0545595963648837,0.0439587522571134,0.0188809019074677,0.00663731414097192],[0.00677998116732583,0.0136766166344597,0.0250199937161132,0.0351437386588164,0.0153200835235364,-0.10269094184081,-0.300294156866944,-0.452193525950744,-0.526820346512151,-0.552864048067155,-0.533740318003105,-0.476274031618956,-0.388894480962361,-0.259813141231144,-0.114547569076005,-0.00853110829773358,0.026270532998724,0.0220705606948521,0.0113720193406875,0.00479006861281537],[0.00441957501535974,0.00778894003230655,0.012540142148981,0.0173167436916603,0.0184411763109792,0.00440344355811548,-0.0360443266925315,-0.0894750888128052,-0.121922064308598,-0.125456895757911,-0.108696702405245,-0.085459967396484,-0.0622076773837985,-0.0357121772079457,-0.0108059125130206,0.00570984074243325,0.0108572435542748,0.00907189266129475,0.00546169557049286,0.00274695672999835],[0.00225324955999086,0.00345783344224472,0.00482546549644145,0.00596820247562728,0.00642314106804783,0.00497815960303374,0.000802829961076174,-0.00466051707841712,-0.00806707180305731,-0.00857575816085395,-0.00712579969234445,-0.00509443595012516,-0.00301562287491784,-0.000558902447204272,0.00185505236696998,0.00354845349115351,0.00396544286363494,0.00334230995206287,0.00226949815936332,0.00133053297176496],[0.000984340193347691,0.0013496359619728,0.00169066836661234,0.00191930093187143,0.001980787260027,0.00175636693773875,0.00122358620658559,0.000576331234525184,0.000147648062675748,-3.54897142083215e-07,7.74015382855556e-05,0.000270581009454098,0.000517610521214735,0.000834734865259236,0.00114835758216744,0.00135844693703667,0.00137028503475841,0.00119199290189003,0.0008900451882533,0.000589631924689919],[0.000402481069886953,0.000507947190207079,0.000593375419375757,0.000641233440522671,0.00064702151846435,0.000601874313523295,0.000513914776167701,0.000410865467976042,0.000333335746125854,0.00028874562991892,0.00028124589461,0.00030274265802603,0.00034398879126769,0.000402287255496514,0.000459948500440884,0.000495061858613304,0.000487579118073008,0.000437016475641103,0.000350497536723171,0.000254936563742146],[0.000163726115550619,0.000195037586347495,0.000218292941710297,0.000230398827193146,0.000231458128184383,0.000221031745330738,0.000202452132495728,0.00018102598729255,0.000163457611590616,0.000151141753612908,0.00014679805188645,0.000150037490389567,0.000158767637217703,0.000171761954889069,0.000184520418412486,0.000191314353707433,0.000187035004073103,0.000171242199650947,0.000144213619097057,0.000112283582046565]],&#34;alpha_stroke&#34;:1,&#34;sizes&#34;:[10,100],&#34;spans&#34;:[1,20],&#34;type&#34;:&#34;surface&#34;}},&#34;layout&#34;:{&#34;margin&#34;:{&#34;b&#34;:40,&#34;l&#34;:60,&#34;t&#34;:25,&#34;r&#34;:10},&#34;scene&#34;:{&#34;xaxis&#34;:{&#34;title&#34;:[]},&#34;yaxis&#34;:{&#34;title&#34;:[]},&#34;zaxis&#34;:{&#34;title&#34;:[]}},&#34;hovermode&#34;:&#34;closest&#34;,&#34;showlegend&#34;:false,&#34;legend&#34;:{&#34;yanchor&#34;:&#34;top&#34;,&#34;y&#34;:0.5}},&#34;source&#34;:&#34;A&#34;,&#34;config&#34;:{&#34;modeBarButtonsToAdd&#34;:[{&#34;name&#34;:&#34;Collaborate&#34;,&#34;icon&#34;:{&#34;width&#34;:1000,&#34;ascent&#34;:500,&#34;descent&#34;:-50,&#34;path&#34;:&#34;M487 375c7-10 9-23 5-36l-79-259c-3-12-11-23-22-31-11-8-22-12-35-12l-263 0c-15 0-29 5-43 15-13 10-23 23-28 37-5 13-5 25-1 37 0 0 0 3 1 7 1 5 1 8 1 11 0 2 0 4-1 6 0 3-1 5-1 6 1 2 2 4 3 6 1 2 2 4 4 6 2 3 4 5 5 7 5 7 9 16 13 26 4 10 7 19 9 26 0 2 0 5 0 9-1 4-1 6 0 8 0 2 2 5 4 8 3 3 5 5 5 7 4 6 8 15 12 26 4 11 7 19 7 26 1 1 0 4 0 9-1 4-1 7 0 8 1 2 3 5 6 8 4 4 6 6 6 7 4 5 8 13 13 24 4 11 7 20 7 28 1 1 0 4 0 7-1 3-1 6-1 7 0 2 1 4 3 6 1 1 3 4 5 6 2 3 3 5 5 6 1 2 3 5 4 9 2 3 3 7 5 10 1 3 2 6 4 10 2 4 4 7 6 9 2 3 4 5 7 7 3 2 7 3 11 3 3 0 8 0 13-1l0-1c7 2 12 2 14 2l218 0c14 0 25-5 32-16 8-10 10-23 6-37l-79-259c-7-22-13-37-20-43-7-7-19-10-37-10l-248 0c-5 0-9-2-11-5-2-3-2-7 0-12 4-13 18-20 41-20l264 0c5 0 10 2 16 5 5 3 8 6 10 11l85 282c2 5 2 10 2 17 7-3 13-7 17-13z m-304 0c-1-3-1-5 0-7 1-1 3-2 6-2l174 0c2 0 4 1 7 2 2 2 4 4 5 7l6 18c0 3 0 5-1 7-1 1-3 2-6 2l-173 0c-3 0-5-1-8-2-2-2-4-4-4-7z m-24-73c-1-3-1-5 0-7 2-2 3-2 6-2l174 0c2 0 5 0 7 2 3 2 4 4 5 7l6 18c1 2 0 5-1 6-1 2-3 3-5 3l-174 0c-3 0-5-1-7-3-3-1-4-4-5-6z&#34;},&#34;click&#34;:&#34;function(gd) { \n        // is this being viewed in RStudio?\n        if (location.search == &#39;?viewer_pane=1&#39;) {\n          alert(&#39;To learn about plotly for collaboration, visit:\\n https://cpsievert.github.io/plotly_book/plot-ly-for-collaboration.html&#39;);\n        } else {\n          window.open(&#39;https://cpsievert.github.io/plotly_book/plot-ly-for-collaboration.html&#39;, &#39;_blank&#39;);\n        }\n      }&#34;}],&#34;cloud&#34;:false},&#34;data&#34;:[{&#34;colorbar&#34;:{&#34;title&#34;:&#34;&#34;,&#34;ticklen&#34;:2,&#34;len&#34;:0.5,&#34;lenmode&#34;:&#34;fraction&#34;,&#34;y&#34;:1,&#34;yanchor&#34;:&#34;top&#34;},&#34;colorscale&#34;:[[&#34;0&#34;,&#34;rgba(68,1,84,1)&#34;],[&#34;0.375819113633513&#34;,&#34;rgba(46,114,142,1)&#34;],[&#34;0.614860784355106&#34;,&#34;rgba(45,171,129,1)&#34;],[&#34;0.668850762064634&#34;,&#34;rgba(55,183,120,1)&#34;],[&#34;0.721250649503678&#34;,&#34;rgba(85,194,106,1)&#34;],[&#34;0.741869696359183&#34;,&#34;rgba(95,198,100,1)&#34;],[&#34;0.759596614205583&#34;,&#34;rgba(102,201,95,1)&#34;],[&#34;0.766444524785076&#34;,&#34;rgba(105,203,93,1)&#34;],[&#34;0.771921533309259&#34;,&#34;rgba(107,204,91,1)&#34;],[&#34;0.774240177609992&#34;,&#34;rgba(108,204,90,1)&#34;],[&#34;0.776393960310481&#34;,&#34;rgba(108,205,89,1)&#34;],[&#34;0.777456624247221&#34;,&#34;rgba(109,205,89,1)&#34;],[&#34;0.777788366286604&#34;,&#34;rgba(109,205,89,1)&#34;],[&#34;0.777905618351944&#34;,&#34;rgba(109,205,89,1)&#34;],[&#34;0.77810407620918&#34;,&#34;rgba(109,205,89,1)&#34;],[&#34;0.77837085979716&#34;,&#34;rgba(109,205,89,1)&#34;],[&#34;0.779175844927974&#34;,&#34;rgba(110,205,89,1)&#34;],[&#34;0.780392583991449&#34;,&#34;rgba(111,205,88,1)&#34;],[&#34;0.782709563725259&#34;,&#34;rgba(113,206,87,1)&#34;],[&#34;0.785645120818855&#34;,&#34;rgba(115,206,87,1)&#34;],[&#34;0.791031953418375&#34;,&#34;rgba(119,207,85,1)&#34;],[&#34;0.804475202718423&#34;,&#34;rgba(128,209,80,1)&#34;],[&#34;0.817609599394738&#34;,&#34;rgba(137,211,76,1)&#34;],[&#34;0.862617764656217&#34;,&#34;rgba(165,218,58,1)&#34;],[&#34;1&#34;,&#34;rgba(253,231,37,1)&#34;]],&#34;showscale&#34;:true,&#34;x&#34;:[-2,-1.79,-1.58,-1.37,-1.16,-0.95,-0.74,-0.53,-0.32,-0.11,0.11,0.32,0.53,0.74,0.95,1.16,1.37,1.58,1.79,2],&#34;y&#34;:[1,1.16,1.32,1.47,1.63,1.79,1.95,2.11,2.26,2.42,2.58,2.74,2.89,3.05,3.21,3.37,3.53,3.68,3.84,4],&#34;z&#34;:[[-3.08284008087714e-05,-6.95055940568146e-05,-0.000152904027610235,-0.000307129199374622,-0.000603336168575354,-0.00107670984843562,-0.00171226369910043,-0.00240874880915773,-0.00295427971153382,-0.00317054647237388,-0.00280952926875751,-0.00196172588475186,-0.00105272569205216,-0.000323960230125378,3.3549517257131e-05,0.000119852559708508,9.61356667690334e-05,5.93721460353743e-05,3.14647681138379e-05,1.58029588207999e-05],[-5.97156266493559e-05,-0.000153088494010707,-0.000387532509628423,-0.000892669522760702,-0.00201640602902329,-0.00404594278989958,-0.00694463181537447,-0.0100057275690944,-0.0119859163758925,-0.0120283711265685,-0.00963624282410412,-0.00596704209154539,-0.0027515914658741,-0.000500846134559077,0.000407598238072749,0.000485581898026756,0.000314646517954195,0.00017103347008332,8.14107830552762e-05,3.74192813287609e-05],[-0.000101627444198409,-0.000301333344533462,-0.000898232088150826,-0.00243441431990618,-0.00649152053922412,-0.0148271879411579,-0.0270315112680516,-0.0374449983586466,-0.0388283465029169,-0.0301817925468875,-0.0172263230031702,-0.00669034984812925,-0.000870561914488886,0.00197750252074761,0.00247649598670947,0.0017710714655731,0.000958124344365332,0.000465610152993699,0.000200220993096641,8.42640062574887e-05],[-0.000128604814171655,-0.000440962030265253,-0.00155556773743255,-0.00500072802176085,-0.0157830111718607,-0.0391865565630043,-0.0647058718962745,-0.0609209903888678,-0.0254246635216605,0.0213731248005544,0.0534323534931901,0.0585823014166358,0.0431002715194586,0.0233890346548393,0.0112657309475754,0.00536020986347699,0.00244888257448314,0.00109063688426224,0.000433192231197526,0.000168959269380315],[-5.35787512105406e-05,-0.000193725916699136,-0.00071984763234496,-0.0024665516752808,-0.00778338414064364,-0.012488888790418,0.00340487085142471,0.0311296079758335,0.05350697699951,0.0789604373028631,0.110144124880591,0.135517408579247,0.125777800734419,0.0746467025094918,0.0237011900823417,0.00439954121958033,0.00155828023525468,0.0010060193941622,0.000519537398411164,0.000229323435681202],[0.000231187815892094,0.001028155057528,0.00502128173702423,0.0212756208079204,0.0704210591732029,0.0977754338871877,0.0567650663573196,0.0287994202941217,0.0207097317586338,0.0210550455213916,0.0272621222368635,0.0375816297686179,0.0429088025060582,0.0243759868905198,-0.0339139628664195,-0.0667488876179007,-0.0338886493262537,-0.00941088994414349,-0.00158339329012525,-0.000124375679941646],[0.00070578158234531,0.00308469810879412,0.0148390754014889,0.0603446183305194,0.158085461671079,0.120993118275384,0.0344675790372146,0.00895908781060817,0.00376636964951738,0.00263854377365913,0.00275033737207775,0.00303010403258119,0.0014060992193039,-0.0106638613391351,-0.0623415435232483,-0.171239414769716,-0.157662323002819,-0.0547482261896157,-0.0104792384390633,-0.00156445878855624],[0.00120944757675567,0.00486009816118491,0.0211982602675762,0.0763932627174608,0.156562830023083,0.0749392028484107,0.00931695344184547,-0.000725702764466818,-0.00112352766913981,-0.000814975010736241,-0.000724799687275901,-0.00106850056599106,-0.00254558529782112,-0.0091595944462225,-0.0391632896923689,-0.147201645441264,-0.242701444321522,-0.113028054189369,-0.0220315040480563,-0.00318557016571292],[0.00165831211253587,0.00573397409548176,0.0204513098643157,0.0552441223744598,0.0605286462669303,-0.0109402112716294,-0.0184175748033502,-0.00868525484471916,-0.00406681240455165,-0.00216461692358394,-0.00156985252088404,-0.00168185358762074,-0.00270702471789352,-0.00694636680186433,-0.0254332208122677,-0.101398748786627,-0.210608338195858,-0.108496962426006,-0.0193501526756375,-0.00229105376373718],[0.00214515762113703,0.00605151361716245,0.0142834428257491,0.00674421627782487,-0.0830113252545907,-0.104858459313984,-0.0476060072654318,-0.0175903928185844,-0.00759174625326553,-0.0038223778548131,-0.00257082153042831,-0.00245700686990069,-0.00337887120162972,-0.00696578141044912,-0.0200801305250857,-0.0647989988406206,-0.108396035876376,-0.0396756946025495,-0.00308192377742362,0.000768520651872757],[0.00301304479020884,0.00681254510602234,0.0055508380609301,-0.0571935625061334,-0.215428108293704,-0.176014098844575,-0.0756923613543237,-0.0297333317385063,-0.0138501640242414,-0.00748645788525681,-0.00522110526972275,-0.00490329419256497,-0.00617291659174912,-0.0104697651230012,-0.0207758523975696,-0.0294517158765599,0.0151969820943215,0.0330428054852378,0.0132472849620316,0.00395833240047616],[0.00463593912761808,0.00972250936398574,0.0043930538171191,-0.0889604124015716,-0.278894733719207,-0.227989726920128,-0.112066633187088,-0.0529076410222092,-0.0294426698025584,-0.0188705628285204,-0.0147931356898146,-0.0144531942736155,-0.0174126729827905,-0.0253946861288933,-0.0370869908410733,-0.0116445645923879,0.0834706357003315,0.0664926685923611,0.0221519578073514,0.00613653868161607],[0.0066687942498245,0.0145874746775531,0.0181229949498726,-0.0499544791683562,-0.261888734053365,-0.29697713307906,-0.197186187941246,-0.124755218146359,-0.0900046015882122,-0.0730233791421587,-0.0667928865377894,-0.0681547654381852,-0.0765354411799265,-0.0931937042562118,-0.101293199597434,-0.0260221675561215,0.0861332499646646,0.064934059311413,0.0237095132839148,0.0071690876821971],[0.0077514196660788,0.0170267426883395,0.030763057913854,0.0207645900610317,-0.116122910138168,-0.32123767976706,-0.369066409714513,-0.345711278582948,-0.331317336368753,-0.332148161327558,-0.337239992428577,-0.33731896888062,-0.328679337590278,-0.298793774248079,-0.208876179406422,-0.0405068102057163,0.0545595963648837,0.0439587522571134,0.0188809019074677,0.00663731414097192],[0.00677998116732583,0.0136766166344597,0.0250199937161132,0.0351437386588164,0.0153200835235364,-0.10269094184081,-0.300294156866944,-0.452193525950744,-0.526820346512151,-0.552864048067155,-0.533740318003105,-0.476274031618956,-0.388894480962361,-0.259813141231144,-0.114547569076005,-0.00853110829773358,0.026270532998724,0.0220705606948521,0.0113720193406875,0.00479006861281537],[0.00441957501535974,0.00778894003230655,0.012540142148981,0.0173167436916603,0.0184411763109792,0.00440344355811548,-0.0360443266925315,-0.0894750888128052,-0.121922064308598,-0.125456895757911,-0.108696702405245,-0.085459967396484,-0.0622076773837985,-0.0357121772079457,-0.0108059125130206,0.00570984074243325,0.0108572435542748,0.00907189266129475,0.00546169557049286,0.00274695672999835],[0.00225324955999086,0.00345783344224472,0.00482546549644145,0.00596820247562728,0.00642314106804783,0.00497815960303374,0.000802829961076174,-0.00466051707841712,-0.00806707180305731,-0.00857575816085395,-0.00712579969234445,-0.00509443595012516,-0.00301562287491784,-0.000558902447204272,0.00185505236696998,0.00354845349115351,0.00396544286363494,0.00334230995206287,0.00226949815936332,0.00133053297176496],[0.000984340193347691,0.0013496359619728,0.00169066836661234,0.00191930093187143,0.001980787260027,0.00175636693773875,0.00122358620658559,0.000576331234525184,0.000147648062675748,-3.54897142083215e-07,7.74015382855556e-05,0.000270581009454098,0.000517610521214735,0.000834734865259236,0.00114835758216744,0.00135844693703667,0.00137028503475841,0.00119199290189003,0.0008900451882533,0.000589631924689919],[0.000402481069886953,0.000507947190207079,0.000593375419375757,0.000641233440522671,0.00064702151846435,0.000601874313523295,0.000513914776167701,0.000410865467976042,0.000333335746125854,0.00028874562991892,0.00028124589461,0.00030274265802603,0.00034398879126769,0.000402287255496514,0.000459948500440884,0.000495061858613304,0.000487579118073008,0.000437016475641103,0.000350497536723171,0.000254936563742146],[0.000163726115550619,0.000195037586347495,0.000218292941710297,0.000230398827193146,0.000231458128184383,0.000221031745330738,0.000202452132495728,0.00018102598729255,0.000163457611590616,0.000151141753612908,0.00014679805188645,0.000150037490389567,0.000158767637217703,0.000171761954889069,0.000184520418412486,0.000191314353707433,0.000187035004073103,0.000171242199650947,0.000144213619097057,0.000112283582046565]],&#34;type&#34;:&#34;surface&#34;,&#34;frame&#34;:null}],&#34;highlight&#34;:{&#34;on&#34;:&#34;plotly_click&#34;,&#34;persistent&#34;:false,&#34;dynamic&#34;:false,&#34;selectize&#34;:false,&#34;opacityDim&#34;:0.2,&#34;selected&#34;:{&#34;opacity&#34;:1},&#34;debounce&#34;:0},&#34;base_url&#34;:&#34;https://plot.ly&#34;},&#34;evals&#34;:[&#34;config.modeBarButtonsToAdd.0.click&#34;],&#34;jsHooks&#34;:[]}&lt;/script&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Touring PITCHf/x Data</title>
      <link>/2015/04/15/touring-pitchf/x-data.html</link>
      <pubDate>Wed, 15 Apr 2015 00:00:00 +0000</pubDate>
      
      <guid>/2015/04/15/touring-pitchf/x-data.html</guid>
      <description>&lt;p&gt;If you haven’t read them already, go check out Brian’s &lt;a href=&#34;https://baseballwithr.wordpress.com/2015/01/11/pitch-classification-with-mclust/&#34;&gt;great&lt;/a&gt; &lt;a href=&#34;https://baseballwithr.wordpress.com/2015/02/22/pitch-classification-with-k-means-clustering/&#34;&gt;posts&lt;/a&gt; on pitch classification and cluster analysis. I particularly like his argument that our goal should be to “Identify all the pitches that can reasonably be classified as ‘different’ from one another”. Grouping observations into similar sets is a very common task in &lt;a href=&#34;http://en.wikipedia.org/wiki/Unsupervised_learning&#34;&gt;unsupervised settings&lt;/a&gt; where a response variable of interest is either unknown or doesn’t exist. There are a mind-boggling number of different methods for “learning” the “best” grouping and Brian has gracefully covered two of them (k-means and model based clustering). Here I’ll present yet another approach that relies on human perception and our ability to recognize patterns.&lt;/p&gt;
&lt;p&gt;In Brian’s post on model based clustering, he visually inspected the fit of the model in the data space with &lt;code&gt;mclust::coordProj()&lt;/code&gt;. This approach is limited in the sense that we can only verify how the model fits onto a scatterplot(s) between two numeric variables, but the whole data space is a higher dimensional beast. Although we are visually limited to 3 dimensions, we can still dynamically explore projections of data in high dimensions in such a way that allows us to construct a mental model of the entire space (commonly referred to as touring multidimensional data).&lt;/p&gt;
&lt;p&gt;There are many ways to tour multidimensional data. The most common are the &lt;em&gt;grand&lt;/em&gt; tour and the &lt;em&gt;guided&lt;/em&gt; tour. The grand tour interpolates through random projections of the data whereas the guided tour progresses through “interesting” projections. In this post, I’ll keep things simple, and we’ll take a grand tour of Mariano Rivera’s pitches from 2011.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data(pitches, package = &amp;quot;pitchRx&amp;quot;)
rivera &amp;lt;- subset(pitches, pitcher_name == &amp;quot;Mariano Rivera&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When I say a grand tour walks through random projections, I really mean that it goes through random &lt;a href=&#34;http://en.wikipedia.org/wiki/Linear_combination&#34;&gt;linear combinations&lt;/a&gt; of all the variables that we give it (subject to some constraints). This is important since this implies that we can’t include categorical variables in the tour. Let’s use the same numeric variables that Brian did when examining Mark Buerhle’s pitches:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;vars &amp;lt;- c(&amp;quot;start_speed&amp;quot;, &amp;quot;break_y&amp;quot;, &amp;quot;break_angle&amp;quot;, &amp;quot;break_length&amp;quot;)
rivera_num &amp;lt;- rivera[names(rivera) %in% vars]
# ensure these variables are numeric
rivera_num[] &amp;lt;- lapply(rivera_num, as.numeric)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With the &lt;a href=&#34;http://www.jstatsoft.org/v40/i02/paper&#34;&gt;&lt;strong&gt;tourr&lt;/strong&gt;&lt;/a&gt; package, it’s really easy to perform the grand tour (although, I’ve had problems running this code inside of RStudio, so you may want to run this outside of RStudio):&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(tourr)
animate(rivera_num, grand_tour(), display_xy())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can actually mimic this functionality and make the results easier to share using &lt;a href=&#34;https://github.com/tdhock/animint&#34;&gt;&lt;strong&gt;animint&lt;/strong&gt;&lt;/a&gt;. In fact, I’ve provided a &lt;a href=&#34;https://gist.github.com/cpsievert/4673815529b7a1e6c1aa&#34;&gt;convenience function&lt;/a&gt; for creating tours of PITCHf/x data called &lt;code&gt;pitch_tour()&lt;/code&gt;. By default, &lt;code&gt;pitch_tour()&lt;/code&gt; will use MLBAM’s pitch type classification for the point color.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;devtools::source_gist(&amp;quot;4673815529b7a1e6c1aa&amp;quot;)
pitch_tour(rivera)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you view the result &lt;a href=&#34;http://cpsievert.github.io/baseballR/20150415/rivera&#34;&gt;here&lt;/a&gt; (best viewed with Chrome), you’ll notice that the projection begins with &lt;code&gt;break_y&lt;/code&gt; on the y-axis and &lt;code&gt;start_speed&lt;/code&gt; on the x-axis. There appears to be 4-5 very distinct groups/clusters of pitches along the &lt;code&gt;break_y&lt;/code&gt; axis (I’ll return to this shortly). As the tour progresses through the random projections, you should also notice that MLBAM’s classification is almost entirely determined by the &lt;code&gt;break_angle&lt;/code&gt; (that is, we could draw a line orthogonal to the &lt;code&gt;break_angle&lt;/code&gt; axis that separates red points from blue points):&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
rivera$break_angle &amp;lt;- as.numeric(rivera$break_angle)
ggplot(rivera, aes(x = break_angle, fill = pitch_type)) + 
  geom_density(alpha = 0.2)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&#34;https://baseballwithr.files.wordpress.com/2015/04/density.png&#34;&gt;&lt;img src=&#34;https://baseballwithr.files.wordpress.com/2015/04/density.png?w=300&#34; alt=&#34;density&#34; width=&#34;300&#34; height=&#34;243&#34; class=&#34;alignnone size-medium wp-image-1344&#34; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;rivera$mlbam_type &amp;lt;- cut(rivera$break_angle, c(-100, 0, 100))
with(rivera, table(mlbam_type, pitch_type))&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;          pitch_type
mlbam_type    FC  FF
  (-100,0]   775   4
  (0,100]     14 119&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, given what we’ve seen in the tour, splitting on &lt;code&gt;break_y&lt;/code&gt; is clearly better if our goal is to produce the most “distinct” grouping (that is, most separated from one another in the data space). In fact, &lt;a href=&#34;http://cpsievert.github.io/baseballR/20150415/rivera-mbc&#34;&gt;a model based clustering mostly agrees with our visual intuition&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;m &amp;lt;- mclust::Mclust(rivera_num)
rivera_num$classification &amp;lt;- m$classification
pitch_tour(rivera_num, color_by = &amp;quot;classification&amp;quot;, out_dir = &amp;quot;rivera-mbc&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Of course, Rivera doesn’t have anywhere near 8 different pitch types. The point here is that the cluster analysis is fooled by the “discreteness” of &lt;code&gt;break_y&lt;/code&gt;. Rivera’s &lt;code&gt;break_y&lt;/code&gt; only varies from 23.6 to 24.0 and the precision of &lt;code&gt;break_y&lt;/code&gt; measurements only goes to the tenth place. Whenever the ratio of precision to range for a numerical variable is this large, it is bound to cause problems, so we should to remove it from consideration for Rivera. Interestingly, Mark Buerhle’s &lt;code&gt;break_y&lt;/code&gt; data is similar to Rivera’s, but the &lt;a href=&#34;http://cpsievert.github.io/baseballR/20150415/mark-mbc&#34;&gt;model based clustering approach doesn’t get fooled as badly&lt;/a&gt;. I suppose that is due to that fact that Mark has a higher number of actual types are more spread out in the data space.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mark &amp;lt;- read.csv(&amp;quot;http://www.brianmmills.com/uploads/2/3/9/3/23936510/markb2013.csv&amp;quot;)
table(mark$break_y)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;23.6 23.7 23.8 23.9   24 
  24  521 2128  668   27 &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;mark_num &amp;lt;- mark[names(mark) %in% vars]
mark_num[] &amp;lt;- lapply(mark_num, as.numeric)
m2 &amp;lt;- mclust::Mclust(mark_num)
mark_num$classification &amp;lt;- m2$classification
pitch_tour(mark_num, color_by = &amp;quot;classification&amp;quot;, out_dir = &amp;quot;mark-mbc&amp;quot;)&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
  </channel>
</rss>