<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/shiny-chat-in-few-lines-of-code/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://appsilondatascience.com/blog?/rstats/2017/07/02/shiny-chat.html"> Appsilon Data Science - R language</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<h2>Intro</h2>
<p>We live in a society heavily reliant upon communication, networking and information exchange. Think about all the chat apps that have recently popped out: WhatsApp, Messenger, Skype, Viber, Slack (not to mention Snapchat or Telegram). They have engrained themselves into our daily lives. You’d be hard pressed to find someone who doesn’t use at least one of these apps on a regular basis; with some using all of them! This leads to the obvious conclusion that written communication has become an integral part of our lives.</p>
<p>You may be thinking that, from a software developers perspective, creating communication apps is difficult, tedious and time consuming. I’m going to convince you otherwise.</p>
<p>We’re going to build a shiny chat app in no more than <strong>15 minutes</strong> and less than <strong>100 lines</strong> of R code!</p>
<h2>App’s architecture</h2>
<p>Let’s start with our chat app design. The focus is going to be basic functionality. All we need for a functioning chat app is a message window (1) to store previous comments, a text input (2) and a send button (3). Let’s also add another text input (4) to identify our users with some nicknames.</p>
<p><img src="https://i2.wp.com/appsilondatascience.com/assets/article_images/2017-07-02-shiny-chat/chatdesign.jpg?w=456" data-recalc-dims="1"></p>
<p>Having laid out out the desired functionality, the question is where to store our data? A text file could be fine, but periodical reading and writing would become unbearable for larger apps. Note that our problem is asynchronous – we want to send a text message only when the user presses a button. The message should then immediately appear on the other user’s screen. You may have heard of the <a rel="nofollow" href="https://www.rethinkdb.com/" target="_blank">RethinkDB</a> open-source database, which is based on JSONs. Its asynchronous nature makes it perfect for realtime apps. Feel free to visit their <a rel="nofollow" href="https://www.rethinkdb.com/faq/" target="_blank">documentation website</a> if you want to learn more about <em>RethinkDB</em>.</p>
<p>For the purpose of this development let’s assume that our database will include records containing: <code>user</code>, <code>text</code> and <code>time</code> fields.</p>
<p>Another more important problem is which framework should we choose to build the app? Although there are several obvious solutions, we are going to take a closer look at R and Shiny. With <code>shiny.collections</code> package it will be as easy as making pie chart in <code>ggplot</code>.</p>
<p>Can’t wait to see how that’s possible? Let’s move on to the code!</p>
<h2>Gimme some code</h2>
<h3>Chat UI</h3>
<p>At the very beginning, let’s create an R script <code>chat.R</code>, which will contain our chat code. As I mentioned above, we will use <code>shiny</code> and <code>shiny.collections</code> packages. They should be attached first.</p>
<figure>
<pre><code data-lang="r"><span>library</span><span>(</span><span>shiny</span><span>)</span><span>
</span><span>library</span><span>(</span><span>shiny.collections</span><span>)</span></code></pre>
</figure>
<p>You can install the latest version of <code>shiny.collections</code> via <code>devtools</code>.</p>
<figure>
<pre><code data-lang="r"><span>devtools</span><span>::</span><span>install_github</span><span>(</span><span>&quot;Appsilon/shiny.collections&quot;</span><span>)</span></code></pre>
</figure>
<p>We might need some other libraries but can add them later.</p>
<p>As you probably know, each Shiny App consists of <code>ui</code>, which contains the app’s layout and <code>server</code> for the app’s logic.</p>
<p>First, we implement the <code>ui</code> part of the app, following the mock-up above.</p>
<figure>
<pre><code data-lang="r"><span>ui</span><span> </span><span>&lt;-</span><span> </span><span>shinyUI</span><span>(</span><span>fluidPage</span><span>(</span><span>
</span><span>titlePanel</span><span>(</span><span>&quot;Chat app (shiny.collections demo)&quot;</span><span>),</span><span>
</span><span>div</span><span>(</span><span>textInput</span><span>(</span><span>&quot;username_field&quot;</span><span>,</span><span> </span><span>&quot;Username&quot;</span><span>,</span><span> </span><span>width</span><span> </span><span>=</span><span> </span><span>&quot;200px&quot;</span><span>)),</span><span>
</span><span>uiOutput</span><span>(</span><span>&quot;chatbox&quot;</span><span>),</span><span>
</span><span>div</span><span>(</span><span>style</span><span> </span><span>=</span><span> </span><span>&quot;display:inline-block&quot;</span><span>,</span><span>
</span><span>textInput</span><span>(</span><span>&quot;message_field&quot;</span><span>,</span><span> </span><span>&quot;Your message&quot;</span><span>,</span><span> </span><span>width</span><span> </span><span>=</span><span> </span><span>&quot;500px&quot;</span><span>)),</span><span>
</span><span>div</span><span>(</span><span>style</span><span> </span><span>=</span><span> </span><span>&quot;display:inline-block&quot;</span><span>,</span><span>
</span><span>actionButton</span><span>(</span><span>&quot;send&quot;</span><span>,</span><span> </span><span>&quot;Send&quot;</span><span>))</span><span>
</span><span>))</span></code></pre>
</figure>
<p>Create an empty server if you want to see the current state of your app:</p>
<figure>
<pre><code data-lang="r"><span>server</span><span> </span><span>&lt;-</span><span> </span><span>shinyServer</span><span>(</span><span> </span><span>function</span><span>(</span><span>input</span><span>,</span><span> </span><span>output</span><span>,</span><span> </span><span>session</span><span>)</span><span> </span><span>{})</span></code></pre>
</figure>
<p>and add <code>shinyApp</code> creator at the end of the file.</p>
<figure>
<pre><code data-lang="r"><span>shinyApp</span><span>(</span><span>ui</span><span> </span><span>=</span><span> </span><span>ui</span><span>,</span><span> </span><span>server</span><span> </span><span>=</span><span> </span><span>server</span><span>)</span></code></pre>
</figure>
<p>After running it you should see something like this:</p>
<p><img src="https://i2.wp.com/appsilondatascience.com/assets/article_images/2017-07-02-shiny-chat/firstlook.jpg?w=456" data-recalc-dims="1"></p>
<h3>App’s logic</h3>
<p>Great! Now that we have the chat design, we can start thinking of adding some functionality. We should ensure that our database is up and running before engaging the items we’ve created so far. If you have RethinkDB properly <a rel="nofollow" href="https://www.rethinkdb.com/docs/install/" target="_blank">installed</a>, using it is a piece of cake. Just type in your shell:</p>
<figure>
<pre><code data-lang="bash"><span>$ </span>rethinkdb</code></pre>
</figure>
<p>If the final line of your shell’s output looks similar to the one below, you are ready to use <code>shiny.collections</code>.</p>
<div>
<pre><code>Server ready, &quot;user_QTG8WL_n0v&quot; 67f1e11d-0acb-4fe9-ac1c-811b9bbecb66
</code></pre>
</div>
<p>The first step is to connect a database. Add the following line just before the server definition.</p>
<figure>
<pre><code data-lang="r"><span>connection</span><span> </span><span>&lt;-</span><span> </span><span>shiny.collections</span><span>::</span><span>connect</span><span>()</span></code></pre>
</figure>
<p>(I am using double colon notation here to avoid ambiguity about which functionality comes from standard <code>shiny</code> and which from <code>shiny.collections</code> package).</p>
<p>By default <code>shiny.collections</code> connects to a database named “shiny”, or creates it if it’s not present.</p>
<p>The initial content in our server will be:</p>
<figure>
<pre><code data-lang="r"><span>chat</span><span> </span><span>&lt;-</span><span> </span><span>shiny.collections</span><span>::</span><span>collection</span><span>(</span><span>&quot;chat&quot;</span><span>,</span><span> </span><span>connection</span><span>)</span></code></pre>
</figure>
<p>It makes a collection from a table named <code>chat</code>. It will be empty until we fill it in.</p>
<p>It’s high time to focus on UI elements. Let’s work from top to bottom. The first component is the username field (4). It should definitely not be empty because we need to identify our users somehow. Let’s fill it with some random values from function <code>get_random_username</code> to start.</p>
<figure>
<pre><code data-lang="r"><span>get_random_username</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>()</span><span> </span><span>{</span><span>
</span><span>paste0</span><span>(</span><span>&quot;User&quot;</span><span>,</span><span> </span><span>round</span><span>(</span><span>runif</span><span>(</span><span>1</span><span>,</span><span> </span><span>10000</span><span>,</span><span> </span><span>99999</span><span>)))</span><span>
</span><span>}</span></code></pre>
</figure>
<p>(You can add all function definitons before <code>ui</code> and <code>server</code> in your script).</p>
<p>The following command added to server will update <code>username_field</code> with the output of the function while we initialize the chat.</p>
<figure>
<pre><code data-lang="r"><span>updateTextInput</span><span>(</span><span>session</span><span>,</span><span> </span><span>&quot;username_field&quot;</span><span>,</span><span>
</span><span>value</span><span> </span><span>=</span><span> </span><span>get_random_username</span><span>()</span><span>
</span><span>)</span></code></pre>
</figure>
<p>Now, we can add some action to the send button:</p>
<figure>
<pre><code data-lang="r"><span>observeEvent</span><span>(</span><span>input</span><span>$</span><span>send</span><span>,</span><span> </span><span>{</span><span>
</span><span># ...
</span><span>})</span></code></pre>
</figure>
<p>First thing to do is to form a data structure to send to our database an R list <code>new_message</code>:</p>
<figure>
<pre><code data-lang="r"><span>new_message</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>user</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>username_field</span><span>,</span><span>
</span><span>text</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>message_field</span><span>,</span><span>
</span><span>time</span><span> </span><span>=</span><span> </span><span>Sys.time</span><span>())</span></code></pre>
</figure>
<p>Then we use <code>insert</code> function from <code>shiny.collections</code>:</p>
<figure>
<pre><code data-lang="r"><span>shiny.collections</span><span>::</span><span>insert</span><span>(</span><span>chat</span><span>,</span><span> </span><span>new_message</span><span>)</span></code></pre>
</figure>
<p>and clear text input.</p>
<figure>
<pre><code data-lang="r"><span>updateTextInput</span><span>(</span><span>session</span><span>,</span><span> </span><span>&quot;message_field&quot;</span><span>,</span><span> </span><span>value</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span></code></pre>
</figure>
<p>Once everything is put together, it should look like this:</p>
<figure>
<pre><code data-lang="r"><span>observeEvent</span><span>(</span><span>input</span><span>$</span><span>send</span><span>,</span><span> </span><span>{</span><span>
</span><span>new_message</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>user</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>username_field</span><span>,</span><span>
</span><span>text</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>message_field</span><span>,</span><span>
</span><span>time</span><span> </span><span>=</span><span> </span><span>Sys.time</span><span>())</span><span>
</span><span>shiny.collections</span><span>::</span><span>insert</span><span>(</span><span>chat</span><span>,</span><span> </span><span>new_message</span><span>)</span><span>
</span><span>updateTextInput</span><span>(</span><span>session</span><span>,</span><span> </span><span>&quot;message_field&quot;</span><span>,</span><span> </span><span>value</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>})</span></code></pre>
</figure>
<p>The data from database will be displayed in <code>chatbox</code> (UI item (1)).</p>
<figure>
<pre><code data-lang="r"><span>output</span><span>$</span><span>chatbox</span><span> </span><span>&lt;-</span><span> </span><span>renderUI</span><span>({</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>is_empty</span><span>(</span><span>chat</span><span>$</span><span>collection</span><span>))</span><span> </span><span>{</span><span>
</span><span>render_msg_divs</span><span>(</span><span>chat</span><span>$</span><span>collection</span><span>)</span><span>
</span><span>}</span><span> </span><span>else</span><span> </span><span>{</span><span>
</span><span>tags</span><span>$</span><span>span</span><span>(</span><span>&quot;Empty chat&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>})</span></code></pre>
</figure>
<p>The <code>observeEvent</code> function allows us to observe <code>chat$collection</code> data and render <code>div</code> with messages only when it changes. There are two conditions here: empty collection and collection with content. Test it with the following logical statement <code>!is_empty(chat$collection)</code>. It employs <code>is_empty</code> function from the <code>purrr</code> package (so don’t forget to add <code>library(purrr)</code> at the beginning of your R script). When it’s empty, your app should simply return a span with an “Empty chat” notification. If not, the chat should display messages with neat formatting. The <code>render_msg_divs</code> function is responsible for that:</p>
<figure>
<pre><code data-lang="r"><span>render_msg_divs</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>collection</span><span>)</span><span> </span><span>{</span><span>
</span><span>div</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>&quot;ui very relaxed list&quot;</span><span>,</span><span>
</span><span>collection</span><span> </span><span>%>%</span><span>
</span><span>arrange</span><span>(</span><span>time</span><span>)</span><span> </span><span>%>%</span><span>
</span><span>by_row</span><span>(</span><span>~</span><span> </span><span>div</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>&quot;item&quot;</span><span>,</span><span>
</span><span>a</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>&quot;header&quot;</span><span>,</span><span> </span><span>.</span><span>$</span><span>user</span><span>),</span><span>
</span><span>div</span><span>(</span><span>class</span><span> </span><span>=</span><span> </span><span>&quot;description&quot;</span><span>,</span><span> </span><span>.</span><span>$</span><span>text</span><span>)</span><span>
</span><span>))</span><span> </span><span>%>%</span><span> </span><span>{</span><span>.</span><span>$</span><span>.out</span><span>}</span><span>
</span><span>)</span><span>
</span><span>}</span></code></pre>
</figure>
<p>I must admit that there is some magic going on there. We use <code>dplyr</code> and <code>purrrlyr</code> to make the code tidy. Our goal is to create a div with messages listed one after another. Using <code>div(class = &quot;ui very relaxed list&quot;, ...)</code> is an easy way to achieve this.</p>
<p>As our <code>collection</code> comes from unstructured noSQL database we first need to sort all items by time <code>collection %>% arrange(time)</code>. Next, for each row we create div named “item” with “header” being username (field user from our <code>chat$collection</code>) and “description” being content of the user’s message (field <code>text</code>).</p>
<p>In order to apply it to every row, we use <code>by_row</code> function from <code>purrrlyr</code> package. The function returns a <code>data.frame</code> with an additional column named <code>.out</code> with results of the operation applied to respective row. With syntax <code>%>% {.$.out}</code> we extract only results of that operation as a list.</p>
<p>To sum up, whole shiny server code should look like this:</p>
<figure>
<pre><code data-lang="r"><span>server</span><span> </span><span>&lt;-</span><span> </span><span>shinyServer</span><span>(</span><span>function</span><span>(</span><span>input</span><span>,</span><span> </span><span>output</span><span>,</span><span> </span><span>session</span><span>)</span><span> </span><span>{</span><span>
</span><span>chat</span><span> </span><span>&lt;-</span><span> </span><span>shiny.collections</span><span>::</span><span>collection</span><span>(</span><span>&quot;chat&quot;</span><span>,</span><span> </span><span>connection</span><span>)</span><span>
</span><span>updateTextInput</span><span>(</span><span>session</span><span>,</span><span> </span><span>&quot;username_field&quot;</span><span>,</span><span>
</span><span>value</span><span> </span><span>=</span><span> </span><span>get_random_username</span><span>()</span><span>
</span><span>)</span><span>
</span><span>observeEvent</span><span>(</span><span>input</span><span>$</span><span>send</span><span>,</span><span> </span><span>{</span><span>
</span><span>new_message</span><span> </span><span>&lt;-</span><span> </span><span>list</span><span>(</span><span>user</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>username_field</span><span>,</span><span>
</span><span>text</span><span> </span><span>=</span><span> </span><span>input</span><span>$</span><span>message_field</span><span>,</span><span>
</span><span>time</span><span> </span><span>=</span><span> </span><span>Sys.time</span><span>())</span><span>
</span><span>shiny.collections</span><span>::</span><span>insert</span><span>(</span><span>chat</span><span>,</span><span> </span><span>new_message</span><span>)</span><span>
</span><span>updateTextInput</span><span>(</span><span>session</span><span>,</span><span> </span><span>&quot;message_field&quot;</span><span>,</span><span> </span><span>value</span><span> </span><span>=</span><span> </span><span>&quot;&quot;</span><span>)</span><span>
</span><span>})</span><span>
</span><span>output</span><span>$</span><span>chatbox</span><span> </span><span>&lt;-</span><span> </span><span>renderUI</span><span>({</span><span>
</span><span>if</span><span> </span><span>(</span><span>!</span><span>is_empty</span><span>(</span><span>chat</span><span>$</span><span>collection</span><span>))</span><span> </span><span>{</span><span>
</span><span>render_msg_divs</span><span>(</span><span>chat</span><span>$</span><span>collection</span><span>)</span><span>
</span><span>}</span><span> </span><span>else</span><span> </span><span>{</span><span>
</span><span>tags</span><span>$</span><span>span</span><span>(</span><span>&quot;Empty chat&quot;</span><span>)</span><span>
</span><span>}</span><span>
</span><span>})</span><span>
</span><span>})</span></code></pre>
</figure>
<p>We’re pretty much ready to run our chat but should consider introducing some amendments beforehand.</p>
<h3>Improving the view</h3>
<p>According to our mock-up with design, the box with messages should be fixed height rectangle but it’s currently just a list. We can fix this by adding this CSS code:</p>
<div>
<pre><code>#chatbox {
  padding: .5em;
  border: 1px solid #777;
  height: 300px;
  overflow-y: scroll;
}
</code></pre>
</div>
<p>To define our customized style in our shiny app we need to add <code>tags$head()</code> at the beginning of our <code>fluidPage</code> definition in UI. Then we insert CSS code. This can be done in two ways: by using <code>HTML</code> command from <code>shiny</code>:</p>
<figure>
<pre><code data-lang="r"><span>tags</span><span>$</span><span>style</span><span>(</span><span>HTML</span><span>(</span><span>&quot;#CSS code&quot;</span><span>))</span></code></pre>
</figure>
<p>or adding a path to CSS file.</p>
<figure>
<pre><code data-lang="r"><span>tags</span><span>$</span><span>link</span><span>(</span><span>rel</span><span> </span><span>=</span><span> </span><span>&quot;stylesheet&quot;</span><span>,</span><span> </span><span>type</span><span> </span><span>=</span><span> </span><span>&quot;text/css&quot;</span><span>,</span><span> </span><span>href</span><span> </span><span>=</span><span> </span><span>&quot;file_with_style.css&quot;</span><span>)</span></code></pre>
</figure>
<p>Commonly, for shiny apps, all external files are stored in a <code>www/</code> folder.</p>
<p>We haven’t finished yet. Our <code>chatbox</code> div has the proper size now, but it is unable to automatically scroll down after receiving a new message. Another issue is that the user is forced to press the <code>send</code> button every time he or she finishes typing a new message. Most modern chat apps allow you to proceed after pressing ENTER. There’s no need for our app to be worse in that regard. We can easily introduce those two functionalities with the following <a rel="nofollow" href="https://github.com/Appsilon/shiny.collections/blob/master/inst/examples/www/script.js" target="_blank">JavaScript code</a> <small>(taken from ShinyChat example: look at <strong>Not less important</strong> section).</small></p>
<p>You can add that script to UI’s head with <code>tags$script</code> command:</p>
<figure>
<pre><code data-lang="r"><span>tags</span><span>$</span><span>script</span><span>(</span><span>src</span><span> </span><span>=</span><span> </span><span>&quot;script.js&quot;</span><span>)</span></code></pre>
</figure>
<h2>Launching the app</h2>
<p>Awesome! You’re ready to launch the chat. If you followed the previous steps carefully you should see a view like this:</p>
<p><img src="https://i1.wp.com/appsilondatascience.com/assets/article_images/2017-07-02-shiny-chat/readyapp.jpg?w=456" data-recalc-dims="1"></p>
<p>Now it’s your turn! Have fun and try to upgrade the chat by adding new functionalities or changing the style.</p>
<h2>Not less important</h2>
<p>You can find the entire code in <code>chat.R</code> script published in <a rel="nofollow" href="https://github.com/Appsilon/shiny.collections" target="_blank">shiny.collections</a> repository in <a rel="nofollow" href="https://github.com/Appsilon/shiny.collections/tree/master/inst/examples" target="_blank">examples</a> folder.</p>
<p>The main inspiration for this demo came from a <strong><a rel="nofollow" href="http://shiny.rstudio.com/gallery/chat-room.html" target="_blank">ShinyChat example</a></strong> from <em>Shiny Gallery</em>. I decided to follow this idea to show that with <code>shiny.collections</code> you can make it faster and easier (<strong>130 vs 60</strong> of lines of pure R code).</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://appsilondatascience.com/blog?/rstats/2017/07/02/shiny-chat.html"> Appsilon Data Science - R language</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/u6p1CSMbkWg" height="1"></a></div>