<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>r2d3 on R Views</title>
    <link>https://rviews.rstudio.com/tags/r2d3/</link>
    <description>Recent content in r2d3 on R Views</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Thu, 20 Sep 2018 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://rviews.rstudio.com/tags/r2d3/" rel="self" type="application/rss+xml" />
    
    
    
    
    <item>
      <title>Interactive plots in Shiny</title>
      <link>https://rviews.rstudio.com/2018/09/20/shiny-r2d3/</link>
      <pubDate>Thu, 20 Sep 2018 00:00:00 +0000</pubDate>
      
      <guid>https://rviews.rstudio.com/2018/09/20/shiny-r2d3/</guid>
      <description>
        


&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-09-17-shiny-r2d3/header.png&#34; /&gt;

&lt;/div&gt;
&lt;p&gt;I wish this post existed when I was struggling to add interactive plots to my Shiny app. I was mainly focused on recreating functionality found in other “dashboarding” applications. When looking for options, I found that &lt;a href=&#34;https://www.htmlwidgets.org/&#34;&gt;htmlwidgets&lt;/a&gt; were the closest to what companies usually expect. However, while they are great for client-side interactivity, I often hit walls with them when I try to add click-through interactivity because the functionality is either not there, is very limited, or is bloated. With &lt;code&gt;r2d3&lt;/code&gt; there is more work, but the gains in customization and interactivity make it by far the best choice, in my opinion.&lt;/p&gt;
&lt;p&gt;I asked a good friend at work to help me test the sample app provided in this post. She was able to run it easily, but then told me that she didn’t know that she was supposed to click on things. Adding interactive plots is one of the most important capabilities to include in a Shiny app. Sadly though, it seems that very few do it. If we wish to offer an alternative to enterprise reporting and BI tools by using Shiny, we need to do our best to match the interactivity those other tools seem to offer out of the box.&lt;/p&gt;
&lt;div id=&#34;the-sample-app&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;The sample app&lt;/h2&gt;
&lt;p&gt;I put together a sample app that should run in your R session by simply copying the code. This will allow us to focus on the details of the approach, and not on the setup.&lt;/p&gt;
&lt;p&gt;A working version of the app is available here: &lt;a href=&#34;https://beta.rstudioconnect.com/content/3940/&#34;&gt;Shiny-r2d3-app&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In this app, we can click on the bars and see the &lt;code&gt;DT&lt;/code&gt; object update based on the value of the bar. When the drop-down changes, the plot will update with a nice transition, as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;d3-is-hard&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;“D3 is hard”&lt;/h2&gt;
&lt;p&gt;The title is a quote of a luminary in the R community. A few months ago, I told him that I wanted to start using &lt;code&gt;r2d3&lt;/code&gt; but was struggling with making heads or tails of D3. This person has forgotten more than I will ever learn about pretty much any subject. If he says it’s hard, then I’m in for a world of hurt. Nevertheless, my naivete and stubbornness prevailed.&lt;/p&gt;
&lt;p&gt;I’ve since discovered that D3 is a language with which the desired result can be obtained by using one of several coding approaches. The more I learn to use it, the more I like its flexibility as a stand-alone visualization language.&lt;/p&gt;
&lt;p&gt;One thing that helped was to realize that D3 and &lt;code&gt;ggplot2&lt;/code&gt; are similar in the amount of flexibility they offer. Picture that what you are drawing for a bar plot are the actual rectangles, almost as if you’re using &lt;code&gt;geom_rect()&lt;/code&gt;. Except that in D3, the 0,0 coordinates are top/left, as opposed to bottom/left, so we have to flip our thinking upside down when we create a visualization with D3. In addition, the vertical and horizontal positions and sizes are expressed in fractions (read: percentages), so there are no absolute positions.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;a-good-way-to-start&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;A good way to start&lt;/h2&gt;
&lt;p&gt;After trying out several approaches, I think that a good way to start is by having a few “primer” D3 scripts that can be modified to suit a particular app.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;r2d3&lt;/code&gt; calls a D3 script with a &lt;code&gt;.js&lt;/code&gt; extension. As a result, the D3 code sits outside the R script, away from view. With &lt;code&gt;r2d3&lt;/code&gt;, a &lt;code&gt;data.frame&lt;/code&gt; can be used to pass all sorts of attributes (x/y coordinates, colors, etc.) to D3.&lt;/p&gt;
&lt;p&gt;A good way of thinking about these “primers” is that you are building your own &lt;code&gt;geom&lt;/code&gt;s as &lt;code&gt;.js&lt;/code&gt; scripts. So, once it’s done, you can pass the regular “right-side-up” coordinate data to &lt;code&gt;r2d3&lt;/code&gt; and it will know how to calculate the proper offsets to place the shapes in the correct spot.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;a-first-primer&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;A first primer&lt;/h2&gt;
&lt;p&gt;The idea in this section is to provide the smallest possible example that covers what I feel are the most important pieces that make up a presentable and functional product. My hope is that, if you find this interesting and useful for your line of work, you will take your time to dissect what each code section does, to learn the principles of this approach. This way, you can customize and even expand on the primer.&lt;/p&gt;
&lt;p&gt;The first example below is not the full primer. Instead, it is the section where most of the nuances of how the primer works exist. I’ll use that to explain some of the mechanics.&lt;/p&gt;
&lt;p&gt;You can copy-paste the following code in your R session and run it without worrying about file dependencies. I know how important that is when learning new things, so I’m using a small workaround to providing &lt;code&gt;r2d3&lt;/code&gt; a separate &lt;code&gt;.js&lt;/code&gt; file by saving the contents of a character variable that contains the D3 script into a temporary file. This is probably not something that you’ll do in a final Shiny app, but it works well for this example. Based on how the R Views’ code highlighter is setup, all of the D3 code will be in red, and the R code mostly in black:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(shiny)
library(dplyr)
library(r2d3)
library(forcats)

# D3 code inside an R character variable
r2d3_script &amp;lt;- &amp;quot;
// !preview r2d3 data= data.frame(y = 0.1, ylabel = &amp;#39;1%&amp;#39;, fill = &amp;#39;#E69F00&amp;#39;, mouseover = &amp;#39;green&amp;#39;, label = &amp;#39;one&amp;#39;, id = 1)
function svg_height() {return parseInt(svg.style(&amp;#39;height&amp;#39;))}
function svg_width()  {return parseInt(svg.style(&amp;#39;width&amp;#39;))}
function col_top()  {return svg_height() * 0.05; }
function col_left() {return svg_width()  * 0.20; }
function actual_max() {return d3.max(data, function (d) {return d.y; }); }
function col_width()  {return (svg_width() / actual_max()) * 0.55; }
function col_heigth() {return svg_height() / data.length * 0.95; }
var bars = svg.selectAll(&amp;#39;rect&amp;#39;).data(data);
bars.enter().append(&amp;#39;rect&amp;#39;)
    .attr(&amp;#39;x&amp;#39;,      col_left())
    .attr(&amp;#39;y&amp;#39;,      function(d, i) { return i * col_heigth() + col_top(); })
    .attr(&amp;#39;width&amp;#39;,  function(d) { return d.y * col_width(); })
    .attr(&amp;#39;height&amp;#39;, col_heigth() * 0.9)
    .attr(&amp;#39;fill&amp;#39;,   function(d) {return d.fill; })
    .attr(&amp;#39;id&amp;#39;,     function(d) {return (d.label); })
    .on(&amp;#39;click&amp;#39;, function(){
      Shiny.setInputValue(&amp;#39;bar_clicked&amp;#39;, d3.select(this).attr(&amp;#39;id&amp;#39;), {priority: &amp;#39;event&amp;#39;});
    })
    .on(&amp;#39;mouseover&amp;#39;, function(){
      d3.select(this).attr(&amp;#39;fill&amp;#39;, function(d) {return d.mouseover; });
    })
    .on(&amp;#39;mouseout&amp;#39;, function(){
      d3.select(this).attr(&amp;#39;fill&amp;#39;, function(d) {return d.fill; });
    });
&amp;quot;
# Save D3 code into a tempfile
r2d3_file &amp;lt;- tempfile()
writeLines(r2d3_script, r2d3_file)

# Shiny app starts here
ui &amp;lt;- fluidPage(
    d3Output(&amp;quot;d3&amp;quot;)
)

server &amp;lt;- function(input, output, session) {
    output$d3 &amp;lt;- renderD3({
        gss_cat %&amp;gt;%
            group_by(marital) %&amp;gt;%
            tally() %&amp;gt;%
            arrange(desc(n)) %&amp;gt;%
            mutate(
                y = n,
                ylabel = prettyNum(n, big.mark = &amp;quot;,&amp;quot;),
                fill = &amp;quot;#E69F00&amp;quot;,
                mouseover = &amp;quot;#0072B2&amp;quot;
            ) %&amp;gt;%
            r2d3(r2d3_file)
            # ^^ Use the temp file containing the D3 code
    })}

shinyApp(ui = ui, server = server)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The result should look like the screenshot below. In your R session, hovering over the bar will change the color. Also notice that the bars do not cover the entire window. This is because there are limits placed in the way of ratios within the functions used on the top of the script.&lt;/p&gt;
&lt;div class=&#34;figure&#34;&gt;
&lt;img src=&#34;/post/2018-09-17-shiny-r2d3/first.png&#34; /&gt;

&lt;/div&gt;
&lt;div id=&#34;code-breakdown&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Code breakdown&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;First, is the D3 code:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I start by defining some canvas size function beginning with: &lt;code&gt;function svg_height() {return parseInt(svg.style(&#39;height&#39;))}&lt;/code&gt;. These allow for the correct relative placement and size, as well as adapting to a window resize. For example: &lt;code&gt;function actual_max() {return d3.max(data, function (d) {return d.y; }); }&lt;/code&gt; obtains the value of the longest bar, and then: &lt;code&gt;function col_width()  {return (svg_width() / actual_max()) * 0.55; }&lt;/code&gt; makes sure that the largest rectangle (representing a bar) drawn is 55% the size of the window. I used to define these as regular D3 variables, but found that as functions, they worked more consistently when running with Shiny.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;With &lt;code&gt;var bars = svg.selectAll(&#39;rect&#39;).data(data);&lt;/code&gt;, we create a new rectangle - better said, a new rectangle set. Just like with &lt;code&gt;geom_rect()&lt;/code&gt;, if you pass a vector with multiple values, it will create multiple rectangles. The last function, &lt;code&gt;data()&lt;/code&gt;, tells D3 to use the &lt;code&gt;data&lt;/code&gt; data set, which is the default name that &lt;code&gt;r2d3&lt;/code&gt; is using when it translates our &lt;code&gt;data.frame&lt;/code&gt; to a D3-friendly format. This is the “secret sauce” that allows us to use that data as attributes of the plot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The rectangles are initially drawn with: &lt;code&gt;bars.enter().append(&#39;rect&#39;)&lt;/code&gt;. This will work fine as long as nothing changes. But with Shiny, we want change, so in a later section, I will introduce the &lt;code&gt;bars.transition()&lt;/code&gt; function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, are the attributes (&lt;code&gt;.attr&lt;/code&gt;). Attributes are interesting in these kinds of objects. They are all named as a character variable (&lt;code&gt;x&lt;/code&gt;, &lt;code&gt;fill&lt;/code&gt;, etc.), so it’s essentially free-form. Each type of D3 shape has its own set of expected attributes, such as &lt;code&gt;x&lt;/code&gt;, &lt;code&gt;y&lt;/code&gt;, and &lt;code&gt;width&lt;/code&gt;, but I can also pass a “made-up” attribute and the script will not fail. In other words, if you pass an attribute of a “reserved” name for the shape. it will be used; for example, &lt;code&gt;r&lt;/code&gt; is the attribute for radius of a D3 circle. But if the attribute does not exist, it just becomes metadata that we can use later on if we want. This comes in handy if we want an ID field to be passed to Shiny, but that ID field is not displayed in the plot. The downside is that a misspelled attribute will fail silently, so it makes debugging a bit difficult. In other words, make sure that your attributes are spelled correctly! In the meantime, defining &lt;code&gt;x&lt;/code&gt; is easy because we want it to be as far to the left as possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Most attributes are set based on data passed via &lt;code&gt;r2d3&lt;/code&gt;. We do that by wrapping the value of the attribute inside a function. We already told D3 where the data comes from, so it is implied that in &lt;code&gt;function(d)&lt;/code&gt; the data object will be represented by &lt;code&gt;d&lt;/code&gt;. Another interesting thing about these functions is the second argument, usually represented by &lt;code&gt;i&lt;/code&gt;. It represents the “row number” of the observation. This means that a function like &lt;code&gt;function(d, i) { return d.x * i}&lt;/code&gt; will give the attribute the value of the &lt;code&gt;x&lt;/code&gt; variable of the &lt;code&gt;data.frame&lt;/code&gt; we passed to &lt;code&gt;r2d3&lt;/code&gt;, times the row number. So &lt;code&gt;.attr(&#39;fill&#39;,   function(d) {return d.fill; })&lt;/code&gt; simply passes the &lt;code&gt;fill&lt;/code&gt; value of our &lt;code&gt;data.frame&lt;/code&gt; to D3. Notice that we can name these fields whatever we want; we just need to map them appropriately. With a primer, I found that it’s better to keep either matching (or at the very least, generic) names so we can use them for other plots.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;on()&lt;/code&gt; functions track named events, such as &lt;code&gt;click&lt;/code&gt;, &lt;code&gt;mouseover&lt;/code&gt;, and &lt;code&gt;mouseout&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;click&lt;/code&gt; function will use a Shiny JavaScript function that makes the interaction possible. In &lt;code&gt;Shiny.setInputValue(&#39;bar_clicked&#39;, d3.select(this).attr(&#39;id&#39;), {priority: &#39;event&#39;});&lt;/code&gt;, I specify the name of the input inside Shiny, so &lt;code&gt;bar_clicked&lt;/code&gt; becomes &lt;code&gt;input$bar_clicked&lt;/code&gt; in R. The attribute &lt;code&gt;id&lt;/code&gt; is the value passed to R via that input. This is only a brief introduction to the topic; a much more detailed explanation with illustrations can be found in the &lt;a href=&#34;https://rstudio.github.io/r2d3/articles/shiny.html#d3-to-shiny&#34;&gt;&lt;code&gt;r2d3&lt;/code&gt; site&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;mouseover&lt;/code&gt; and &lt;code&gt;mouseout&lt;/code&gt; events are used to get the color-changing, hover-over effect. On &lt;code&gt;mouseover&lt;/code&gt;, the &lt;code&gt;fill&lt;/code&gt; attribute is updated to use the highlighting color and then restore it to the original color when the pointer leaves with &lt;code&gt;mouseout&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;For the R/Shiny code:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;As mentioned above, using &lt;code&gt;r2d3_file &amp;lt;- tempfile()&lt;/code&gt; and then &lt;code&gt;writeLines(r2d3_script, r2d3_file)&lt;/code&gt; is done to keep the D3 and R code in one location. This allows you to copy and run the script without worrying about dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;r2d3&lt;/code&gt; includes functions to interact with Shiny. The &lt;code&gt;d3Output()&lt;/code&gt; function is used in the &lt;code&gt;ui&lt;/code&gt; section of the app, and &lt;code&gt;renderD3()&lt;/code&gt; is used in the &lt;code&gt;server&lt;/code&gt; section of the app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using &lt;code&gt;dplyr&lt;/code&gt;, the &lt;code&gt;forcats::gss_cat&lt;/code&gt; data is transformed to fit what the primer expects. In other words, the variable that the total count obtained with &lt;code&gt;tally()&lt;/code&gt; is renamed to &lt;code&gt;y&lt;/code&gt;. Additionally, new fields are added to specify the colors. A note about colors with D3: you can pass color names (“red”), or the Hex code of the color (“#E69F00”). Some additional tips for Hex color selection can be found in the &lt;a href=&#34;http://www.cookbook-r.com/Graphs/Colors_(ggplot2)/#a-colorblind-friendly-palette&#34;&gt;&lt;code&gt;ggplot2&lt;/code&gt; cookbook&lt;/a&gt;. A very nice application to test different color schemes and explore contrast with different color deficiencies is &lt;a href=&#34;http://projects.susielu.com/viz-palette&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thanks to the fact that the &lt;code&gt;r2d3()&lt;/code&gt; function uses the data as its first argument, we can simply pipe (&lt;code&gt;%&amp;gt;%&lt;/code&gt;) the &lt;code&gt;dplyr&lt;/code&gt; transformations directly to it. The only argument to pass to &lt;code&gt;r2d3()&lt;/code&gt; is the location of the new temporary file.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;the-full-example&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;The full example&lt;/h2&gt;
&lt;p&gt;Here is the full code for the sample app linked above. The D3 script is what I would consider a more complete “primer” that you can use in other apps. Copy and run the code to try out the Shiny app; as mentioned before, it should run without having to worry about any other file dependencies. More explanation and code breakdown is available after this code section:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(shiny)
library(dplyr)
library(r2d3)
library(forcats)
library(DT)
library(rlang)

r2d3_script &amp;lt;- &amp;quot;
// !preview r2d3 data= data.frame(y = 0.1, ylabel = &amp;#39;1%&amp;#39;, fill = &amp;#39;#E69F00&amp;#39;, mouseover = &amp;#39;green&amp;#39;, label = &amp;#39;one&amp;#39;, id = 1)
function svg_height() {return parseInt(svg.style(&amp;#39;height&amp;#39;))}
function svg_width()  {return parseInt(svg.style(&amp;#39;width&amp;#39;))}
function col_top()  {return svg_height() * 0.05; }
function col_left() {return svg_width()  * 0.20; }
function actual_max() {return d3.max(data, function (d) {return d.y; }); }
function col_width()  {return (svg_width() / actual_max()) * 0.55; }
function col_heigth() {return svg_height() / data.length * 0.95; }

var bars = svg.selectAll(&amp;#39;rect&amp;#39;).data(data);
bars.enter().append(&amp;#39;rect&amp;#39;)
    .attr(&amp;#39;x&amp;#39;,      col_left())
    .attr(&amp;#39;y&amp;#39;,      function(d, i) { return i * col_heigth() + col_top(); })
    .attr(&amp;#39;width&amp;#39;,  function(d) { return d.y * col_width(); })
    .attr(&amp;#39;height&amp;#39;, col_heigth() * 0.9)
    .attr(&amp;#39;fill&amp;#39;,   function(d) {return d.fill; })
    .attr(&amp;#39;id&amp;#39;,     function(d) {return (d.label); })
    .on(&amp;#39;click&amp;#39;, function(){
      Shiny.setInputValue(&amp;#39;bar_clicked&amp;#39;, d3.select(this).attr(&amp;#39;id&amp;#39;), {priority: &amp;#39;event&amp;#39;});
    })
    .on(&amp;#39;mouseover&amp;#39;, function(){
      d3.select(this).attr(&amp;#39;fill&amp;#39;, function(d) {return d.mouseover; });
    })
    .on(&amp;#39;mouseout&amp;#39;, function(){
      d3.select(this).attr(&amp;#39;fill&amp;#39;, function(d) {return d.fill; });
    });
bars.transition()
  .duration(500)
    .attr(&amp;#39;x&amp;#39;,      col_left())
    .attr(&amp;#39;y&amp;#39;,      function(d, i) { return i * col_heigth() + col_top(); })
    .attr(&amp;#39;width&amp;#39;,  function(d) { return d.y * col_width(); })
    .attr(&amp;#39;height&amp;#39;, col_heigth() * 0.9)
    .attr(&amp;#39;fill&amp;#39;,   function(d) {return d.fill; })
    .attr(&amp;#39;id&amp;#39;,     function(d) {return d.label; });
bars.exit().remove();

// Identity labels
var txt = svg.selectAll(&amp;#39;text&amp;#39;).data(data);
txt.enter().append(&amp;#39;text&amp;#39;)
    .attr(&amp;#39;x&amp;#39;, width * 0.01)
    .attr(&amp;#39;y&amp;#39;, function(d, i) { return i * col_heigth() + (col_heigth() / 2) + col_top(); })
    .text(function(d) {return d.label; })
    .style(&amp;#39;font-family&amp;#39;, &amp;#39;sans-serif&amp;#39;);
txt.transition()
    .duration(1000)
    .attr(&amp;#39;x&amp;#39;, width * 0.01)
    .attr(&amp;#39;y&amp;#39;, function(d, i) { return i * col_heigth() + (col_heigth() / 2) + col_top(); })
    .text(function(d) {return d.label; });
txt.exit().remove();

// Numeric labels
var totals = svg.selectAll().data(data);
totals.enter().append(&amp;#39;text&amp;#39;)
    .attr(&amp;#39;x&amp;#39;, function(d) { return ((d.y * col_width()) + col_left()) * 1.01; })
    .attr(&amp;#39;y&amp;#39;, function(d, i) { return i * col_heigth() + (col_heigth() / 2) + col_top(); })
    .style(&amp;#39;font-family&amp;#39;, &amp;#39;sans-serif&amp;#39;)
    .text(function(d) {return d.ylabel; });
totals.transition()
    .duration(1000)
    .attr(&amp;#39;x&amp;#39;, function(d) { return ((d.y * col_width()) + col_left()) * 1.01; })
    .attr(&amp;#39;y&amp;#39;, function(d, i) { return i * col_heigth() + (col_heigth() / 2) + col_top(); })
    .attr(&amp;#39;d&amp;#39;, function(d) { return d.x; })
    .text(function(d) {return d.ylabel; });
totals.exit().remove();
&amp;quot;
r2d3_file &amp;lt;- tempfile()
writeLines(r2d3_script, r2d3_file)

ui &amp;lt;- fluidPage(
  selectInput(&amp;quot;var&amp;quot;, &amp;quot;Variable&amp;quot;,
              list(&amp;quot;marital&amp;quot;, &amp;quot;rincome&amp;quot;, &amp;quot;partyid&amp;quot;, &amp;quot;relig&amp;quot;, &amp;quot;denom&amp;quot;),
              selected = &amp;quot;marital&amp;quot;),
  d3Output(&amp;quot;d3&amp;quot;),
  DT::dataTableOutput(&amp;quot;table&amp;quot;),
  textInput(&amp;quot;val&amp;quot;, &amp;quot;Value&amp;quot;, &amp;quot;Married&amp;quot;)
)

server &amp;lt;- function(input, output, session) {
  output$d3 &amp;lt;- renderD3({
    gss_cat %&amp;gt;%
      mutate(label = !!sym(input$var)) %&amp;gt;%
      group_by(label) %&amp;gt;%
      tally() %&amp;gt;%
      arrange(desc(n)) %&amp;gt;%
      mutate(
        y = n,
        ylabel = prettyNum(n, big.mark = &amp;quot;,&amp;quot;),
        fill = ifelse(label != input$val, &amp;quot;#E69F00&amp;quot;, &amp;quot;red&amp;quot;),
        mouseover = &amp;quot;#0072B2&amp;quot;
      ) %&amp;gt;%
      r2d3(r2d3_file)
  })
  observeEvent(input$bar_clicked, {
      updateTextInput(session, &amp;quot;val&amp;quot;, value = input$bar_clicked)
  })
  output$table &amp;lt;- renderDataTable({
    gss_cat %&amp;gt;%
      filter(!!sym(input$var) == input$val) %&amp;gt;%
      datatable()
  })
}

shinyApp(ui = ui, server = server)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;additions-to-d3-code&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Additions to D3 code&lt;/h3&gt;
&lt;p&gt;Hopefully, you can see a coding pattern emerging in the more lengthy example above. Here are some explanations for items that are new or outside the pattern:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;bars.transition()&lt;/code&gt; function “re-draws” the shape or text when the underlying data changes, when we make a change within the Shiny app. The &lt;code&gt;duration()&lt;/code&gt; function defines the time that the changes take. Be sure to copy all of the attributes from the &lt;code&gt;enter()&lt;/code&gt; function. This is needed when adding D3 plots into a Shiny app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;code&gt;var txt = svg.selectAll(&#39;text&#39;).data(data);&lt;/code&gt; code adds a new text object, similar to &lt;code&gt;geom_text()&lt;/code&gt;. The same coding pattern as the &lt;code&gt;rect&lt;/code&gt; shape applies. The additions are: a &lt;code&gt;text()&lt;/code&gt; function that defines what its displayed on screen (note that there’s no &lt;code&gt;attr(&#39;text&#39;,...&lt;/code&gt;), and the &lt;code&gt;style()&lt;/code&gt; function to allow setting the font type size.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div id=&#34;setting-up-the-shiny-interactivity&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Setting up the Shiny interactivity&lt;/h3&gt;
&lt;p&gt;There are three options to integrate the Shiny input created inside the D3 script:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;p&gt;Have a given Shiny &lt;code&gt;output&lt;/code&gt; react to the D3/Shiny input. An example would be to use it as a value to filter data in &lt;code&gt;filter(id_field == input$bar_clicked)&lt;/code&gt;. This works OK when there are not too many plots to integrate, but for a large dashboard, the second option would be better. An example of this approach can be found &lt;a href=&#34;https://rstudio.github.io/r2d3/articles/shiny.html#shiny-code&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Shiny’s &lt;code&gt;observeEvent()&lt;/code&gt; to monitor the D3/Shiny input and have it run a specific action based on the value of the input. I usually use this approach to update another Shiny input in the app, and that is the approach used in this app.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use the &lt;code&gt;reactive()&lt;/code&gt; function to wrap all of the data transformations that are common across all of the plots inside the dashboard. Then have each plot use that function as the base of further &lt;code&gt;dplyr&lt;/code&gt; transformations. That approach can be found in the &lt;a href=&#34;http://db.rstudio.com/best-practices/dashboards/&#34;&gt;Enterprise Dashboards article&lt;/a&gt; on db.rstudio.com; here is &lt;a href=&#34;https://github.com/sol-eng/db-dashboard/blob/f3f42eabe722207510e6670ad81e36722e0b3d44/local_app.R#L91-L116&#34;&gt;a direct link to the code&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div id=&#34;other-r-additions&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Other R additions&lt;/h3&gt;
&lt;p&gt;A few additional tips that are helpful, but not mandatory:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To get the effect of keeping the selected bar with a different color than the others, I used an &lt;code&gt;ifelse()&lt;/code&gt; inside the &lt;code&gt;mutate()&lt;/code&gt; that checks if a particular row matches to the selected &lt;code&gt;input&lt;/code&gt;: &lt;code&gt;fill = ifelse(label != input$val, &amp;quot;#E69F00&amp;quot;, &amp;quot;red&amp;quot;)&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In this line: &lt;code&gt;mutate(label = !!sym(input$var))&lt;/code&gt;, I am using &lt;code&gt;rlang&lt;/code&gt;’s convention to allow for the plot to change the field that it is displaying. This is a very rare requirement in an app, so I hope that it doesn’t throw anyone off. This is an advanced R programming concept not necessary for D3/Shiny.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I decided to use a separate field with the total count (&lt;code&gt;y&lt;/code&gt;) and the label that will be shown in that bar (&lt;code&gt;ylabel&lt;/code&gt;). It was easier for me to edit the format in R than in D3. Some may decide to do that in the D3 script.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;rstudio-1.2&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;RStudio 1.2&lt;/h2&gt;
&lt;p&gt;If you have the RStudio IDE Preview Release installed, you can easily preview the D3 visualization right in the Viewer pane. Information on how to do this is &lt;a href=&#34;https://rstudio.github.io/r2d3/#d3-preview&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the first line in the script above, there is a D3 comment line with metadata that RStudio will pass to &lt;code&gt;r2d3&lt;/code&gt; so that you do not run R code in the console to see a preview. This integration also lets us use the IDE to edit the D3 file, which accelerates learning D3.&lt;/p&gt;
&lt;p&gt;To try this out with the visualization above, copy and paste the contents of the &lt;code&gt;r2d3_script&lt;/code&gt; variable to a new D3 file inside the RStudio IDE.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;closing-words&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Closing words&lt;/h2&gt;
&lt;p&gt;Thank you for making it this far! Even if you were just skimming, I hope one or two things I’ve shown were interesting enough to consider trying out the exercise.&lt;/p&gt;
&lt;p&gt;Sometimes, we forget how far we have progressed on a subject and forget what it feels like to begin the learning process. Hopefully these explanations avoid this pitfall and will simplify your learning experience. Please feel free to ask questions or start a topic of discussion at &lt;a href=&#34;https://community.rstudio.com/&#34;&gt;community.rstudio.com&lt;/a&gt;, where many are happy to help!&lt;/p&gt;
&lt;p&gt;Here are some additional links to resources that you may want to check out. The first two I wrote for RStudio documentation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;https://rstudio.github.io/r2d3/articles/shiny.html&#34;&gt;Using r2d3 with Shiny&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href=&#34;http://db.rstudio.com/best-practices/dashboards/#using-r2d3-for-interactivity-and-drill-down&#34;&gt;Enterprise-ready dashboards&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href=&#34;https://github.com/d3/d3/blob/master/API.md&#34;&gt;D3 API reference&lt;/a&gt; is really good, I use it often.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;a href=&#34;https://rstudio.github.io/r2d3/&#34;&gt;&lt;code&gt;r2d3&lt;/code&gt; site&lt;/a&gt; has a great Gallery and articles to review. It has a section about &lt;a href=&#34;https://rstudio.github.io/r2d3/articles/learning_d3.html&#34;&gt;learning D3&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

        &lt;script&gt;window.location.href=&#39;https://rviews.rstudio.com/2018/09/20/shiny-r2d3/&#39;;&lt;/script&gt;
      </description>
    </item>
    
  </channel>
</rss>
